diff --git a/pom.xml b/pom.xml index c735adb80..99710d0b7 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,7 @@ org.seleniumhq.selenium selenium-java - 2.53.0 + 2.53.1 cglib diff --git a/src/main/java/io/appium/java_client/AppiumDriver.java b/src/main/java/io/appium/java_client/AppiumDriver.java index 1e54423fe..b41879151 100644 --- a/src/main/java/io/appium/java_client/AppiumDriver.java +++ b/src/main/java/io/appium/java_client/AppiumDriver.java @@ -35,6 +35,7 @@ import static io.appium.java_client.MobileCommand.REMOVE_APP; import static io.appium.java_client.MobileCommand.RUN_APP_IN_BACKGROUND; import static io.appium.java_client.MobileCommand.SET_SETTINGS; +import static io.appium.java_client.MobileCommand.prepareArguments; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -46,7 +47,6 @@ import io.appium.java_client.service.local.AppiumDriverLocalService; import io.appium.java_client.service.local.AppiumServiceBuilder; -import org.apache.commons.lang3.StringUtils; import org.openqa.selenium.By; import org.openqa.selenium.Capabilities; import org.openqa.selenium.Dimension; @@ -57,7 +57,6 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.html5.Location; -import org.openqa.selenium.remote.CommandInfo; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.DriverCommand; import org.openqa.selenium.remote.ErrorHandler; @@ -67,7 +66,6 @@ import org.openqa.selenium.remote.Response; import org.openqa.selenium.remote.html5.RemoteLocationContext; import org.openqa.selenium.remote.http.HttpClient; -import org.openqa.selenium.remote.http.HttpMethod; import org.openqa.selenium.remote.internal.JsonToWebElementConverter; import java.lang.reflect.Constructor; @@ -189,39 +187,6 @@ protected static Capabilities substituteMobilePlatform(Capabilities originalCapa return dc; } - /** - * @param param is a parameter name. - * @param value is the parameter value. - * @return built {@link ImmutableMap}. - */ - protected static ImmutableMap getCommandImmutableMap(String param, - Object value) { - ImmutableMap.Builder builder = ImmutableMap.builder(); - builder.put(param, value); - return builder.build(); - } - - /** - * @param params is the array with parameter names. - * @param values is the array with parameter values. - * @return built {@link ImmutableMap}. - */ - protected static ImmutableMap getCommandImmutableMap(String[] params, - Object[] values) { - ImmutableMap.Builder builder = ImmutableMap.builder(); - for (int i = 0; i < params.length; i++) { - if (!StringUtils.isBlank(params[i]) && (values[i] != null)) { - builder.put(params[i], values[i]); - } - } - return builder.build(); - } - - @SuppressWarnings("unused") - private static CommandInfo deleteC(String url) { - return new CommandInfo(url, HttpMethod.DELETE); - } - @Override public List findElements(By by) { return super.findElements(by); } @@ -572,7 +537,7 @@ public JsonObject getSettings() { * @param settings Map of setting keys and values. */ private void setSettings(ImmutableMap settings) { - execute(SET_SETTINGS, getCommandImmutableMap("settings", settings)); + execute(SET_SETTINGS, prepareArguments("settings", settings)); } /** @@ -584,7 +549,7 @@ private void setSettings(ImmutableMap settings) { * @param value value of the setting. */ protected void setSetting(AppiumSetting setting, Object value) { - setSettings(getCommandImmutableMap(setting.toString(), value)); + setSettings(prepareArguments(setting.toString(), value)); } @Override public WebDriver context(String name) { @@ -654,7 +619,7 @@ protected void setSetting(AppiumSetting setting, Object value) { * @see HasAppStrings#getAppStringMap(String). */ @Override public Map getAppStringMap(String language) { - Response response = execute(GET_STRINGS, getCommandImmutableMap("language", language)); + Response response = execute(GET_STRINGS, prepareArguments("language", language)); return (Map) response.getValue(); } @@ -667,7 +632,7 @@ protected void setSetting(AppiumSetting setting, Object value) { @Override public Map getAppStringMap(String language, String stringFile) { String[] parameters = new String[] {"language", "stringFile"}; Object[] values = new Object[] {language, stringFile}; - Response response = execute(GET_STRINGS, getCommandImmutableMap(parameters, values)); + Response response = execute(GET_STRINGS, prepareArguments(parameters, values)); return (Map) response.getValue(); } diff --git a/src/main/java/io/appium/java_client/CommandExecutionHelper.java b/src/main/java/io/appium/java_client/CommandExecutionHelper.java new file mode 100644 index 000000000..393f0e388 --- /dev/null +++ b/src/main/java/io/appium/java_client/CommandExecutionHelper.java @@ -0,0 +1,41 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * 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.remote.Response; + +import java.util.Map; + +public final class CommandExecutionHelper { + + public static T execute(MobileElement element, + Map.Entry> keyValuePair) { + return handleResponse(element.execute(keyValuePair.getKey(), keyValuePair.getValue())); + } + + public static T execute(MobileDriver driver, + Map.Entry> keyValuePair) { + return handleResponse(driver.execute(keyValuePair.getKey(), keyValuePair.getValue())); + } + + private static T handleResponse(Response responce) { + if (responce != null) { + return (T) responce.getValue(); + } + return null; + } +} diff --git a/src/main/java/io/appium/java_client/MobileCommand.java b/src/main/java/io/appium/java_client/MobileCommand.java index dcd7f2000..8249902a9 100644 --- a/src/main/java/io/appium/java_client/MobileCommand.java +++ b/src/main/java/io/appium/java_client/MobileCommand.java @@ -18,9 +18,11 @@ import com.google.common.collect.ImmutableMap; +import org.apache.commons.lang3.StringUtils; import org.openqa.selenium.remote.CommandInfo; import org.openqa.selenium.remote.http.HttpMethod; +import java.util.HashMap; import java.util.Map; /** @@ -28,93 +30,150 @@ * wire protocol. */ public class MobileCommand { + //General + protected static final String RESET = "reset"; + protected static final String GET_STRINGS = "getStrings"; + protected static final String SET_VALUE = "setValue"; + protected static final String PULL_FILE = "pullFile"; + protected static final String PULL_FOLDER = "pullFolder"; + protected static final String HIDE_KEYBOARD = "hideKeyboard"; + protected static final String RUN_APP_IN_BACKGROUND = "runAppInBackground"; + protected static final String PERFORM_TOUCH_ACTION = "performTouchAction"; + protected static final String PERFORM_MULTI_TOUCH = "performMultiTouch"; + protected static final String IS_APP_INSTALLED = "isAppInstalled"; + protected static final String INSTALL_APP = "installApp"; + protected static final String REMOVE_APP = "removeApp"; + protected static final String LAUNCH_APP = "launchApp"; + protected static final String CLOSE_APP = "closeApp"; + protected static final String LOCK = "lock"; + protected static final String COMPLEX_FIND = "complexFind"; + protected static final String GET_SETTINGS = "getSettings"; + protected static final String SET_SETTINGS = "setSettings"; + protected static final String GET_DEVICE_TIME = "getDeviceTime"; + protected static final String GET_SESSION = "getSession"; + //iOS + protected static final String SHAKE = "shake"; + //Android + protected static final String CURRENT_ACTIVITY = "currentActivity"; + protected static final String END_TEST_COVERAGE = "endTestCoverage"; + protected static final String GET_NETWORK_CONNECTION = "getNetworkConnection"; + protected static final String IS_LOCKED = "isLocked"; + protected static final String LONG_PRESS_KEY_CODE = "longPressKeyCode"; + protected static final String OPEN_NOTIFICATIONS = "openNotifications"; + protected static final String PRESS_KEY_CODE = "pressKeyCode"; + protected static final String PUSH_FILE = "pushFile"; + protected static final String SET_NETWORK_CONNECTION = "setNetworkConnection"; + protected static final String START_ACTIVITY = "startActivity"; + protected static final String TOGGLE_LOCATION_SERVICES = "toggleLocationServices"; + protected static final String UNLOCK = "unlock"; + protected static final String REPLACE_VALUE = "replaceValue"; - public static final String RESET = "reset"; - public static final String GET_STRINGS = "getStrings"; - public static final String PRESS_KEY_CODE = "pressKeyCode"; - public static final String LONG_PRESS_KEY_CODE = "longPressKeyCode"; - public static final String CURRENT_ACTIVITY = "currentActivity"; - public static final String SET_VALUE = "setValue"; - public static final String REPLACE_VALUE = "replaceValue"; - public static final String PULL_FILE = "pullFile"; - public static final String PUSH_FILE = "pushFile"; - public static final String PULL_FOLDER = "pullFolder"; - public static final String HIDE_KEYBOARD = "hideKeyboard"; - public static final String RUN_APP_IN_BACKGROUND = "runAppInBackground"; - public static final String PERFORM_TOUCH_ACTION = "performTouchAction"; - public static final String PERFORM_MULTI_TOUCH = "performMultiTouch"; - public static final String IS_APP_INSTALLED = "isAppInstalled"; - public static final String INSTALL_APP = "installApp"; - public static final String REMOVE_APP = "removeApp"; - public static final String LAUNCH_APP = "launchApp"; - public static final String CLOSE_APP = "closeApp"; - public static final String END_TEST_COVERAGE = "endTestCoverage"; - public static final String LOCK = "lock"; - public static final String IS_LOCKED = "isLocked"; - public static final String SHAKE = "shake"; - public static final String COMPLEX_FIND = "complexFind"; - public static final String OPEN_NOTIFICATIONS = "openNotifications"; - public static final String GET_NETWORK_CONNECTION = "getNetworkConnection"; - public static final String SET_NETWORK_CONNECTION = "setNetworkConnection"; - public static final String GET_SETTINGS = "getSettings"; - public static final String SET_SETTINGS = "setSettings"; - public static final String START_ACTIVITY = "startActivity"; - public static final String TOGGLE_LOCATION_SERVICES = "toggleLocationServices"; - public static final String GET_DEVICE_TIME = "getDeviceTime"; - public static final String UNLOCK = "unlock"; - public static final String GET_SESSION = "getSession"; - public static final Map commandRepository = getMobileCommands(); + public static final Map commandRepository = createCommandRepository(); + private static Map createCommandRepository() { + HashMap result = new HashMap(); + result.put(RESET, postC("/session/:sessionId/appium/app/reset")); + result.put(GET_STRINGS, postC("/session/:sessionId/appium/app/strings")); + result.put(SET_VALUE, postC("/session/:sessionId/appium/element/:id/value")); + result.put(PULL_FILE, postC("/session/:sessionId/appium/device/pull_file")); + result.put(PULL_FOLDER, postC("/session/:sessionId/appium/device/pull_folder")); + result.put(HIDE_KEYBOARD, postC("/session/:sessionId/appium/device/hide_keyboard")); + result.put(RUN_APP_IN_BACKGROUND, postC("/session/:sessionId/appium/app/background")); + result.put(PERFORM_TOUCH_ACTION, postC("/session/:sessionId/touch/perform")); + result.put(PERFORM_MULTI_TOUCH, postC("/session/:sessionId/touch/multi/perform")); + result.put(IS_APP_INSTALLED, postC("/session/:sessionId/appium/device/app_installed")); + result.put(INSTALL_APP, postC("/session/:sessionId/appium/device/install_app")); + result.put(REMOVE_APP, postC("/session/:sessionId/appium/device/remove_app")); + result.put(LAUNCH_APP, postC("/session/:sessionId/appium/app/launch")); + result.put(CLOSE_APP, postC("/session/:sessionId/appium/app/close")); + result.put(LOCK, postC("/session/:sessionId/appium/device/lock")); + result.put(COMPLEX_FIND, postC("/session/:sessionId/appium/app/complex_find")); + result.put(GET_SETTINGS, getC("/session/:sessionId/appium/settings")); + result.put(SET_SETTINGS, postC("/session/:sessionId/appium/settings")); + result.put(GET_DEVICE_TIME, getC("/session/:sessionId/appium/device/system_time")); + result.put(GET_SESSION,getC("/session/:sessionId/")); + //iOS + result.put(SHAKE, postC("/session/:sessionId/appium/device/shake")); + //Android + result.put(CURRENT_ACTIVITY, + getC("/session/:sessionId/appium/device/current_activity")); + result.put(END_TEST_COVERAGE, + postC("/session/:sessionId/appium/app/end_test_coverage")); + result.put(GET_NETWORK_CONNECTION, getC("/session/:sessionId/network_connection")); + result.put(IS_LOCKED, postC("/session/:sessionId/appium/device/is_locked")); + result.put(LONG_PRESS_KEY_CODE, + postC("/session/:sessionId/appium/device/long_press_keycode")); + result.put(OPEN_NOTIFICATIONS, + postC("/session/:sessionId/appium/device/open_notifications")); + result.put(PRESS_KEY_CODE, + postC("/session/:sessionId/appium/device/press_keycode")); + result.put(PUSH_FILE, postC("/session/:sessionId/appium/device/push_file")); + result.put(SET_NETWORK_CONNECTION, + postC("/session/:sessionId/network_connection")); + result.put(START_ACTIVITY, + postC("/session/:sessionId/appium/device/start_activity")); + result.put(TOGGLE_LOCATION_SERVICES, + postC("/session/:sessionId/appium/device/toggle_location_services")); + result.put(UNLOCK, postC("/session/:sessionId/appium/device/unlock")); + result.put(REPLACE_VALUE, postC("/session/:sessionId/appium/element/:id/replace_value")); + return result; + } + + /** + * This methods forms GET commands. + * + * @param url is the command URL + * @return an instance of {@link org.openqa.selenium.remote.CommandInfo} + */ public static CommandInfo getC(String url) { return new CommandInfo(url, HttpMethod.GET); } + /** + * This methods forms POST commands. + * + * @param url is the command URL + * @return an instance of {@link org.openqa.selenium.remote.CommandInfo} + */ public static CommandInfo postC(String url) { return new CommandInfo(url, HttpMethod.POST); } - private static Map getMobileCommands() { - if (commandRepository != null) { - return commandRepository; - } + /** + * This methods forms DELETE commands. + * + * @param url is the command URL + * @return an instance of {@link org.openqa.selenium.remote.CommandInfo} + */ + public static CommandInfo deleteC(String url) { + return new CommandInfo(url, HttpMethod.DELETE); + } - ImmutableMap.Builder builder = ImmutableMap.builder(); - builder.put(RESET, postC("/session/:sessionId/appium/app/reset")) - .put(GET_STRINGS, postC("/session/:sessionId/appium/app/strings")) - .put(PRESS_KEY_CODE, postC("/session/:sessionId/appium/device/press_keycode")) - .put(LONG_PRESS_KEY_CODE, postC("/session/:sessionId/appium/device/long_press_keycode")) - .put(CURRENT_ACTIVITY, getC("/session/:sessionId/appium/device/current_activity")) - .put(SET_VALUE, postC("/session/:sessionId/appium/element/:id/value")) - .put(REPLACE_VALUE, postC("/session/:sessionId/appium/element/:id/replace_value")) - .put(PULL_FILE, postC("/session/:sessionId/appium/device/pull_file")) - .put(PULL_FOLDER, postC("/session/:sessionId/appium/device/pull_folder")) - .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")) - .put(PERFORM_TOUCH_ACTION, postC("/session/:sessionId/touch/perform")) - .put(PERFORM_MULTI_TOUCH, postC("/session/:sessionId/touch/multi/perform")) - .put(IS_APP_INSTALLED, postC("/session/:sessionId/appium/device/app_installed")) - .put(INSTALL_APP, postC("/session/:sessionId/appium/device/install_app")) - .put(REMOVE_APP, postC("/session/:sessionId/appium/device/remove_app")) - .put(LAUNCH_APP, postC("/session/:sessionId/appium/app/launch")) - .put(CLOSE_APP, postC("/session/:sessionId/appium/app/close")) - .put(END_TEST_COVERAGE, postC("/session/:sessionId/appium/app/end_test_coverage")) - .put(LOCK, postC("/session/:sessionId/appium/device/lock")) - .put(IS_LOCKED, postC("/session/:sessionId/appium/device/is_locked")) - .put(SHAKE, postC("/session/:sessionId/appium/device/shake")) - .put(COMPLEX_FIND, postC("/session/:sessionId/appium/app/complex_find")) - .put(OPEN_NOTIFICATIONS, postC("/session/:sessionId/appium/device/open_notifications")) - .put(GET_NETWORK_CONNECTION, getC("/session/:sessionId/network_connection")) - .put(SET_NETWORK_CONNECTION, postC("/session/:sessionId/network_connection")) - .put(GET_SETTINGS, getC("/session/:sessionId/appium/settings")) - .put(SET_SETTINGS, postC("/session/:sessionId/appium/settings")) - .put(START_ACTIVITY, postC("/session/:sessionId/appium/device/start_activity")) - .put(TOGGLE_LOCATION_SERVICES, - postC("/session/:sessionId/appium/device/toggle_location_services")) - .put(GET_DEVICE_TIME, getC("/session/:sessionId/appium/device/system_time")) - .put(UNLOCK, postC("/session/:sessionId/appium/device/unlock")) - .put(GET_SESSION,getC("/session/:sessionId/")); + /** + * @param param is a parameter name. + * @param value is the parameter value. + * @return built {@link ImmutableMap}. + */ + protected static ImmutableMap prepareArguments(String param, + Object value) { + ImmutableMap.Builder builder = ImmutableMap.builder(); + builder.put(param, value); + return builder.build(); + } + /** + * @param params is the array with parameter names. + * @param values is the array with parameter values. + * @return built {@link ImmutableMap}. + */ + protected static ImmutableMap prepareArguments(String[] params, + Object[] values) { + ImmutableMap.Builder builder = ImmutableMap.builder(); + for (int i = 0; i < params.length; i++) { + if (!StringUtils.isBlank(params[i]) && (values[i] != null)) { + builder.put(params[i], values[i]); + } + } return builder.build(); } } diff --git a/src/main/java/io/appium/java_client/android/AndroidDriver.java b/src/main/java/io/appium/java_client/android/AndroidDriver.java index 3ff12cc97..2ba445996 100644 --- a/src/main/java/io/appium/java_client/android/AndroidDriver.java +++ b/src/main/java/io/appium/java_client/android/AndroidDriver.java @@ -16,26 +16,25 @@ package io.appium.java_client.android; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static io.appium.java_client.MobileCommand.CURRENT_ACTIVITY; -import static io.appium.java_client.MobileCommand.END_TEST_COVERAGE; -import static io.appium.java_client.MobileCommand.GET_NETWORK_CONNECTION; -import static io.appium.java_client.MobileCommand.IS_LOCKED; -import static io.appium.java_client.MobileCommand.LOCK; -import static io.appium.java_client.MobileCommand.LONG_PRESS_KEY_CODE; -import static io.appium.java_client.MobileCommand.OPEN_NOTIFICATIONS; -import static io.appium.java_client.MobileCommand.PRESS_KEY_CODE; -import static io.appium.java_client.MobileCommand.PUSH_FILE; -import static io.appium.java_client.MobileCommand.SET_NETWORK_CONNECTION; -import static io.appium.java_client.MobileCommand.START_ACTIVITY; -import static io.appium.java_client.MobileCommand.TOGGLE_LOCATION_SERVICES; -import static io.appium.java_client.MobileCommand.UNLOCK; - -import com.google.common.collect.ImmutableMap; + +import static io.appium.java_client.android.AndroidMobileCommandHelper.currentActivityCommand; +import static io.appium.java_client.android.AndroidMobileCommandHelper.endTestCoverageCommand; +import static io.appium.java_client.android.AndroidMobileCommandHelper.getNetworkConnectionCommand; +import static io.appium.java_client.android.AndroidMobileCommandHelper.isLockedCommand; +import static io.appium.java_client.android.AndroidMobileCommandHelper.lockDeviceCommand; +import static io.appium.java_client.android.AndroidMobileCommandHelper.longPressKeyCodeCommand; +import static io.appium.java_client.android.AndroidMobileCommandHelper.openNotificationsCommand; +import static io.appium.java_client.android.AndroidMobileCommandHelper.pressKeyCodeCommand; +import static io.appium.java_client.android.AndroidMobileCommandHelper.pushFileCommandCommand; +import static io.appium.java_client.android.AndroidMobileCommandHelper.setConnectionCommand; +import static io.appium.java_client.android.AndroidMobileCommandHelper.startActivityCommand; +import static io.appium.java_client.android.AndroidMobileCommandHelper.toggleLocationServicesCommand; +import static io.appium.java_client.android.AndroidMobileCommandHelper.unlockCommand; import io.appium.java_client.AppiumDriver; import io.appium.java_client.AppiumSetting; +import io.appium.java_client.CommandExecutionHelper; import io.appium.java_client.FindsByAndroidUIAutomator; import io.appium.java_client.android.internal.JsonToAndroidElementConverter; import io.appium.java_client.remote.MobilePlatform; @@ -43,12 +42,10 @@ import io.appium.java_client.service.local.AppiumServiceBuilder; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.FileUtils; -import org.apache.commons.lang3.StringUtils; import org.openqa.selenium.Capabilities; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.HttpCommandExecutor; -import org.openqa.selenium.remote.Response; import org.openqa.selenium.remote.http.HttpClient; import java.io.File; @@ -195,7 +192,7 @@ public AndroidDriver(Capabilities desiredCapabilities) { * @param key code for the key pressed on the device. */ @Override public void pressKeyCode(int key) { - execute(PRESS_KEY_CODE, getCommandImmutableMap("keycode", key)); + CommandExecutionHelper.execute(this, pressKeyCodeCommand(key)); } /** @@ -206,9 +203,7 @@ public AndroidDriver(Capabilities desiredCapabilities) { * @see AndroidDeviceActionShortcuts#pressKeyCode(int, Integer). */ @Override public void pressKeyCode(int key, Integer metastate) { - String[] parameters = new String[] {"keycode", "metastate"}; - Object[] values = new Object[] {key, metastate}; - execute(PRESS_KEY_CODE, getCommandImmutableMap(parameters, values)); + CommandExecutionHelper.execute(this, pressKeyCodeCommand(key, metastate)); } /** @@ -217,7 +212,7 @@ public AndroidDriver(Capabilities desiredCapabilities) { * @param key code for the long key pressed on the device. */ @Override public void longPressKeyCode(int key) { - execute(LONG_PRESS_KEY_CODE, getCommandImmutableMap("keycode", key)); + CommandExecutionHelper.execute(this, longPressKeyCodeCommand(key)); } /** @@ -228,21 +223,15 @@ public AndroidDriver(Capabilities desiredCapabilities) { * @see AndroidDeviceActionShortcuts#pressKeyCode(int, Integer) */ @Override public void longPressKeyCode(int key, Integer metastate) { - String[] parameters = new String[] {"keycode", "metastate"}; - Object[] values = new Object[] {key, metastate}; - execute(LONG_PRESS_KEY_CODE, getCommandImmutableMap(parameters, values)); + CommandExecutionHelper.execute(this, longPressKeyCodeCommand(key, metastate)); } @Override public void setConnection(Connection connection) { - String[] parameters = new String[] {"name", "parameters"}; - Object[] values = - new Object[] {"network_connection", ImmutableMap.of("type", connection.bitMask)}; - execute(SET_NETWORK_CONNECTION, getCommandImmutableMap(parameters, values)); + CommandExecutionHelper.execute(this, setConnectionCommand(connection)); } @Override public Connection getConnection() { - Response response = execute(GET_NETWORK_CONNECTION); - int bitMask = Integer.parseInt(response.getValue().toString()); + long bitMask = CommandExecutionHelper.execute(this, getNetworkConnectionCommand()); Connection[] types = Connection.values(); for (Connection connection: types) { @@ -255,9 +244,7 @@ public AndroidDriver(Capabilities desiredCapabilities) { } @Override public void pushFile(String remotePath, byte[] base64Data) { - String[] parameters = new String[] {"path", "data"}; - Object[] values = new Object[] {remotePath, base64Data}; - execute(PUSH_FILE, getCommandImmutableMap(parameters, values)); + CommandExecutionHelper.execute(this, pushFileCommandCommand(remotePath, base64Data)); } @Override public void pushFile(String remotePath, File file) throws IOException { @@ -276,31 +263,9 @@ public AndroidDriver(Capabilities desiredCapabilities) { String intentCategory, String intentFlags, String optionalIntentArguments,boolean stopApp ) throws IllegalArgumentException { - - checkArgument((!StringUtils.isBlank(appPackage) - && !StringUtils.isBlank(appActivity)), - String.format("'%s' and '%s' are required.", "appPackage", "appActivity")); - - appWaitPackage = !StringUtils.isBlank(appWaitPackage) ? appWaitPackage : ""; - appWaitActivity = !StringUtils.isBlank(appWaitActivity) ? appWaitActivity : ""; - intentAction = !StringUtils.isBlank(intentAction) ? intentAction : ""; - intentCategory = !StringUtils.isBlank(intentCategory) ? intentCategory : ""; - intentFlags = !StringUtils.isBlank(intentFlags) ? intentFlags : ""; - optionalIntentArguments = !StringUtils.isBlank(optionalIntentArguments) - ? optionalIntentArguments : ""; - - ImmutableMap parameters = ImmutableMap - .builder().put("appPackage", appPackage) - .put("appActivity", appActivity) - .put("appWaitPackage", appWaitPackage) - .put("appWaitActivity", appWaitActivity) - .put("dontStopAppOnReset", !stopApp) - .put("intentAction", intentAction) - .put("intentCategory", intentCategory) - .put("intentFlags", intentFlags) - .put("optionalIntentArguments", optionalIntentArguments) - .build(); - execute(START_ACTIVITY, parameters); + CommandExecutionHelper.execute(this, startActivityCommand(appPackage, appActivity, + appWaitPackage, appWaitActivity, intentAction, intentCategory, intentFlags, + optionalIntentArguments, stopApp)); } @@ -344,9 +309,7 @@ public void startActivity(String appPackage, String appActivity, * @param path path to .ec file. */ public void endTestCoverage(String intent, String path) { - String[] parameters = new String[] {"intent", "path"}; - Object[] values = new Object[] {intent, path}; - execute(END_TEST_COVERAGE, getCommandImmutableMap(parameters, values)); + CommandExecutionHelper.execute(this, endTestCoverageCommand(intent, path)); } /** @@ -355,15 +318,14 @@ public void endTestCoverage(String intent, String path) { * @return a current activity being run on the mobile device. */ public String currentActivity() { - Response response = execute(CURRENT_ACTIVITY); - return response.getValue().toString(); + return CommandExecutionHelper.execute(this, currentActivityCommand()); } /** * Open the notification shade, on Android devices. */ public void openNotifications() { - execute(OPEN_NOTIFICATIONS); + CommandExecutionHelper.execute(this, openNotificationsCommand()); } /** @@ -372,12 +334,11 @@ public void openNotifications() { * @return true if device is locked. False otherwise */ public boolean isLocked() { - Response response = execute(IS_LOCKED); - return Boolean.parseBoolean(response.getValue().toString()); + return CommandExecutionHelper.execute(this, isLockedCommand()); } public void toggleLocationServices() { - execute(TOGGLE_LOCATION_SERVICES); + CommandExecutionHelper.execute(this, toggleLocationServicesCommand()); } /** @@ -398,35 +359,33 @@ public void ignoreUnimportantViews(Boolean compress) { * @throws WebDriverException This method is not * applicable with browser/webview UI. */ - @SuppressWarnings("unchecked") @Override public T findElementByAndroidUIAutomator(String using) throws WebDriverException { - return (T) findElement("-android uiautomator", using); + return findElement("-android uiautomator", using); } /** * @throws WebDriverException This method is not * applicable with browser/webview UI. */ - @SuppressWarnings("unchecked") @Override public List findElementsByAndroidUIAutomator(String using) throws WebDriverException { - return (List) findElements("-android uiautomator", using); + return findElements("-android uiautomator", using); } /** * This method locks a device. */ public void lockDevice() { - execute(LOCK, ImmutableMap.of("seconds", 0)); + CommandExecutionHelper.execute(this, lockDeviceCommand()); } /** * This method unlocks a device. */ public void unlockDevice() { - execute(UNLOCK); + CommandExecutionHelper.execute(this, unlockCommand()); } } diff --git a/src/main/java/io/appium/java_client/android/AndroidElement.java b/src/main/java/io/appium/java_client/android/AndroidElement.java index 8bb762993..82bab2088 100644 --- a/src/main/java/io/appium/java_client/android/AndroidElement.java +++ b/src/main/java/io/appium/java_client/android/AndroidElement.java @@ -16,10 +16,10 @@ package io.appium.java_client.android; -import com.google.common.collect.ImmutableMap; +import static io.appium.java_client.android.AndroidMobileCommandHelper.replaceElementValueCommand; +import io.appium.java_client.CommandExecutionHelper; import io.appium.java_client.FindsByAndroidUIAutomator; -import io.appium.java_client.MobileCommand; import io.appium.java_client.MobileElement; import org.openqa.selenium.WebDriverException; @@ -50,9 +50,7 @@ public class AndroidElement extends MobileElement * This method replace current text value. * @param value a new value */ - @SuppressWarnings({"rawtypes", "unchecked"}) public void replaceValue(String value) { - ImmutableMap.Builder builder = ImmutableMap.builder(); - builder.put("id", getId()).put("value", new String[] {value}); - execute(MobileCommand.REPLACE_VALUE, builder.build()); + public void replaceValue(String value) { + CommandExecutionHelper.execute(this, replaceElementValueCommand(this, value)); } } diff --git a/src/main/java/io/appium/java_client/android/AndroidMobileCommandHelper.java b/src/main/java/io/appium/java_client/android/AndroidMobileCommandHelper.java new file mode 100644 index 000000000..2ebd75b43 --- /dev/null +++ b/src/main/java/io/appium/java_client/android/AndroidMobileCommandHelper.java @@ -0,0 +1,298 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * 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.android; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.collect.ImmutableMap; + +import io.appium.java_client.MobileCommand; + +import org.apache.commons.lang3.StringUtils; +import org.openqa.selenium.internal.HasIdentity; + +import java.util.AbstractMap; +import java.util.Map; + +/** + * This util class helps to prepare parameters of Android-specific JSONWP + * commands. + */ +public class AndroidMobileCommandHelper extends MobileCommand { + + /** + * This method forms a {@link java.util.Map} of parameters for the + * getting of the current activity. + * + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> currentActivityCommand() { + return new AbstractMap.SimpleEntry>(CURRENT_ACTIVITY, ImmutableMap.of()); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * ending of the test coverage. + * + * @param intent intent to broadcast. + * @param path path to .ec file. + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> endTestCoverageCommand(String intent, + String path) { + String[] parameters = new String[] {"intent", "path"}; + Object[] values = new Object[] {intent, path}; + return new AbstractMap.SimpleEntry>(END_TEST_COVERAGE, prepareArguments(parameters, values)); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * getting of a network connection value. + * + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> getNetworkConnectionCommand() { + return new AbstractMap.SimpleEntry>(GET_NETWORK_CONNECTION, ImmutableMap.of()); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * checking of the device state (is it locked or not). + * + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> isLockedCommand() { + return new AbstractMap.SimpleEntry>(IS_LOCKED, ImmutableMap.of()); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * key event invocation. + * + * @param key code for the key pressed on the device. + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> pressKeyCodeCommand(int key) { + return new AbstractMap.SimpleEntry>(PRESS_KEY_CODE, prepareArguments("keycode", key)); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * key event invocation. + * + * @param key code for the key pressed on the Android device. + * @param metastate metastate for the keypress. + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> pressKeyCodeCommand(int key, + Integer metastate) { + String[] parameters = new String[] {"keycode", "metastate"}; + Object[] values = new Object[] {key, metastate}; + return new AbstractMap.SimpleEntry>(PRESS_KEY_CODE, prepareArguments(parameters, values)); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * long key event invocation. + * + * @param key code for the long key pressed on the device. + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> longPressKeyCodeCommand(int key) { + return new AbstractMap.SimpleEntry>(LONG_PRESS_KEY_CODE, prepareArguments("keycode", key)); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * long key event invocation. + * + * @param key code for the long key pressed on the Android device. + * @param metastate metastate for the long key press. + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> longPressKeyCodeCommand(int key, + Integer metastate) { + String[] parameters = new String[] {"keycode", "metastate"}; + Object[] values = new Object[] {key, metastate}; + return new AbstractMap.SimpleEntry>(LONG_PRESS_KEY_CODE, prepareArguments(parameters, values)); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * notification opening. + * + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> openNotificationsCommand() { + return new AbstractMap.SimpleEntry>(OPEN_NOTIFICATIONS, ImmutableMap.of()); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * file pushing + * + * @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 + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> pushFileCommandCommand(String remotePath, + byte[] base64Data) { + String[] parameters = new String[] {"path", "data"}; + Object[] values = new Object[] {remotePath, base64Data}; + return new AbstractMap.SimpleEntry>(PUSH_FILE, prepareArguments(parameters, values)); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * setting of device network connection. + * + * @param connection The bitmask of the desired connection + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> setConnectionCommand(Connection connection) { + String[] parameters = new String[] {"name", "parameters"}; + Object[] values = + new Object[] {"network_connection", ImmutableMap.of("type", connection.bitMask)}; + return new AbstractMap.SimpleEntry>(SET_NETWORK_CONNECTION, prepareArguments(parameters, values)); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * activity starting. + * + * @param appPackage The package containing the activity. [Required] + * @param appActivity The activity to start. [Required] + * @param appWaitPackage Automation will begin after this package starts. [Optional] + * @param appWaitActivity Automation will begin after this activity starts. [Optional] + * @param intentAction Intent action which will be used to start activity [Optional] + * @param intentCategory Intent category which will be used to start activity [Optional] + * @param intentFlags Flags that will be used to start activity [Optional] + * @param optionalIntentArguments Additional intent arguments that will be used to + * start activity [Optional] + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + * @throws IllegalArgumentException when any required argument is empty + */ + public static Map.Entry> startActivityCommand(String appPackage, + String appActivity, String appWaitPackage, String appWaitActivity, + String intentAction, String intentCategory, String intentFlags, + String optionalIntentArguments, boolean stopApp) throws IllegalArgumentException { + + checkArgument((!StringUtils.isBlank(appPackage) + && !StringUtils.isBlank(appActivity)), + String.format("'%s' and '%s' are required.", "appPackage", "appActivity")); + + String targetWaitPackage = !StringUtils.isBlank(appWaitPackage) ? appWaitPackage : ""; + String targetWaitActivity = !StringUtils.isBlank(appWaitActivity) ? appWaitActivity : ""; + String targetIntentAction = !StringUtils.isBlank(intentAction) ? intentAction : ""; + String targetIntentCategory = !StringUtils.isBlank(intentCategory) ? intentCategory : ""; + String targetIntentFlags = !StringUtils.isBlank(intentFlags) ? intentFlags : ""; + String targetOptionalIntentArguments = !StringUtils.isBlank(optionalIntentArguments) + ? optionalIntentArguments : ""; + + ImmutableMap parameters = ImmutableMap + .builder().put("appPackage", appPackage) + .put("appActivity", appActivity) + .put("appWaitPackage", targetWaitPackage) + .put("appWaitActivity", targetWaitActivity) + .put("dontStopAppOnReset", !stopApp) + .put("intentAction", targetIntentAction) + .put("intentCategory", targetIntentCategory) + .put("intentFlags", targetIntentFlags) + .put("optionalIntentArguments", targetOptionalIntentArguments) + .build(); + return new AbstractMap.SimpleEntry>(START_ACTIVITY, parameters); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * toggling of location services. + * + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> toggleLocationServicesCommand() { + return new AbstractMap.SimpleEntry>(TOGGLE_LOCATION_SERVICES, ImmutableMap.of()); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * device unlocking. + * + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> unlockCommand() { + return new AbstractMap.SimpleEntry>(UNLOCK, ImmutableMap.of()); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * device locking. + * + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> lockDeviceCommand() { + return new AbstractMap.SimpleEntry>(LOCK, prepareArguments("seconds", 0)); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the element + * value replacement. It is used against input elements + * + * @param hasIdentityObject an instance which contains an element ID + * @param value a new value + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> replaceElementValueCommand( + HasIdentity hasIdentityObject, String value) { + String[] parameters = new String[] {"id", "value"}; + Object[] values = + new Object[] {hasIdentityObject.getId(), value}; + + return new AbstractMap.SimpleEntry>(REPLACE_VALUE, prepareArguments(parameters, values)); + } +} diff --git a/src/main/java/io/appium/java_client/ios/IOSDriver.java b/src/main/java/io/appium/java_client/ios/IOSDriver.java index d7587823b..3c8d839f8 100644 --- a/src/main/java/io/appium/java_client/ios/IOSDriver.java +++ b/src/main/java/io/appium/java_client/ios/IOSDriver.java @@ -16,13 +16,12 @@ package io.appium.java_client.ios; -import static io.appium.java_client.MobileCommand.HIDE_KEYBOARD; -import static io.appium.java_client.MobileCommand.LOCK; -import static io.appium.java_client.MobileCommand.SHAKE; - -import com.google.common.collect.ImmutableMap; +import static io.appium.java_client.ios.IOSMobileCommandHelper.hideKeyboardCommand; +import static io.appium.java_client.ios.IOSMobileCommandHelper.lockDeviceCommand; +import static io.appium.java_client.ios.IOSMobileCommandHelper.shakeCommand; import io.appium.java_client.AppiumDriver; +import io.appium.java_client.CommandExecutionHelper; import io.appium.java_client.FindsByIosUIAutomation; import io.appium.java_client.ios.internal.JsonToIOSElementConverter; import io.appium.java_client.remote.MobilePlatform; @@ -176,44 +175,40 @@ public IOSDriver(Capabilities desiredCapabilities) { * @see IOSDeviceActionShortcuts#hideKeyboard(String, String). */ @Override public void hideKeyboard(String strategy, String keyName) { - String[] parameters = new String[] {"strategy", "key"}; - Object[] values = new Object[] {strategy, keyName}; - execute(HIDE_KEYBOARD, getCommandImmutableMap(parameters, values)); + CommandExecutionHelper.execute(this, hideKeyboardCommand(strategy, keyName)); } /** * @see IOSDeviceActionShortcuts#hideKeyboard(String). */ @Override public void hideKeyboard(String keyName) { - execute(HIDE_KEYBOARD, ImmutableMap.of("keyName", keyName)); + CommandExecutionHelper.execute(this, hideKeyboardCommand(keyName)); } /** * @see IOSDeviceActionShortcuts#shake(). */ @Override public void shake() { - execute(SHAKE); + CommandExecutionHelper.execute(this, shakeCommand()); } /** * @throws WebDriverException * This method is not applicable with browser/webview UI. */ - @SuppressWarnings("unchecked") @Override public T findElementByIosUIAutomation(String using) throws WebDriverException { - return (T) findElement("-ios uiautomation", using); + return findElement("-ios uiautomation", using); } /** * @throws WebDriverException This method is not applicable with browser/webview UI. */ - @SuppressWarnings("unchecked") @Override public List findElementsByIosUIAutomation(String using) throws WebDriverException { - return (List) findElements("-ios uiautomation", using); + return findElements("-ios uiautomation", using); } /** @@ -223,6 +218,6 @@ public List findElementsByIosUIAutomation(String using) * @param seconds number of seconds to lock the screen for */ public void lockDevice(int seconds) { - execute(LOCK, ImmutableMap.of("seconds", seconds)); + CommandExecutionHelper.execute(this, lockDeviceCommand(seconds)); } } diff --git a/src/main/java/io/appium/java_client/ios/IOSMobileCommandHelper.java b/src/main/java/io/appium/java_client/ios/IOSMobileCommandHelper.java new file mode 100644 index 000000000..4de1bb8c7 --- /dev/null +++ b/src/main/java/io/appium/java_client/ios/IOSMobileCommandHelper.java @@ -0,0 +1,84 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * 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.ios; + +import com.google.common.collect.ImmutableMap; + +import io.appium.java_client.MobileCommand; + +import java.util.AbstractMap; +import java.util.Map; + +public class IOSMobileCommandHelper extends MobileCommand { + + /** + * This method forms a {@link java.util.Map} of parameters for the + * keyboard hiding. + * + * @param keyName The button pressed by the mobile driver to attempt hiding the + * keyboard. + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> hideKeyboardCommand(String keyName) { + return new AbstractMap.SimpleEntry>(HIDE_KEYBOARD, prepareArguments("keyName", keyName)); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * keyboard hiding. + * + * @param strategy HideKeyboardStrategy. + * @param keyName a String, representing the text displayed on the button of the + * keyboard you want to press. For example: "Done". + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> hideKeyboardCommand(String strategy, + String keyName) { + String[] parameters = new String[] {"strategy", "key"}; + Object[] values = new Object[] {strategy, keyName}; + return new AbstractMap.SimpleEntry>(HIDE_KEYBOARD, prepareArguments(parameters, values)); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * device locking. + * + * @param seconds seconds number of seconds to lock the screen for + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> lockDeviceCommand(int seconds) { + return new AbstractMap.SimpleEntry>(LOCK, prepareArguments("seconds", seconds)); + } + + /** + * This method forms a {@link java.util.Map} of parameters for the + * device shaking. + * + * @return a key-value pair. The key is the command name. The value is a + * {@link java.util.Map} command arguments. + */ + public static Map.Entry> shakeCommand() { + return new AbstractMap.SimpleEntry>(SHAKE, ImmutableMap.of()); + } +}