From 9cc4912fd8483186c1af3fd07db4e6e6ce7cbb31 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Thu, 13 Apr 2023 22:16:13 +0200 Subject: [PATCH 1/3] refactor: Replace non-W3C API calls with corresponding extension calls --- .../java_client/CommandExecutionHelper.java | 21 ++++++ .../appium/java_client/InteractsWithApps.java | 70 +++++++++---------- .../io/appium/java_client/MobileCommand.java | 61 ++++++++++++++++ 3 files changed, 116 insertions(+), 36 deletions(-) diff --git a/src/main/java/io/appium/java_client/CommandExecutionHelper.java b/src/main/java/io/appium/java_client/CommandExecutionHelper.java index 00557b6da..98532c389 100644 --- a/src/main/java/io/appium/java_client/CommandExecutionHelper.java +++ b/src/main/java/io/appium/java_client/CommandExecutionHelper.java @@ -18,8 +18,14 @@ import org.openqa.selenium.remote.Response; +import javax.annotation.Nullable; +import java.util.AbstractMap; +import java.util.Collections; +import java.util.HashMap; import java.util.Map; +import static org.openqa.selenium.remote.DriverCommand.EXECUTE_SCRIPT; + public final class CommandExecutionHelper { public static T execute(ExecutesMethod executesMethod, @@ -27,6 +33,21 @@ public static T execute(ExecutesMethod executesMethod, return handleResponse(executesMethod.execute(keyValuePair.getKey(), keyValuePair.getValue())); } + public static T executeScript(ExecutesMethod executesMethod, String scriptName) { + return executeScript(executesMethod, scriptName, null); + } + + public static T executeScript( + ExecutesMethod executesMethod, String scriptName, @Nullable Map args + ) { + Map payload = new HashMap<>(); + payload.put("script", scriptName); + if (args != null) { + payload.put("args", args.isEmpty() ? Collections.emptyList() : Collections.singletonList(args)); + } + return CommandExecutionHelper.execute(executesMethod, new AbstractMap.SimpleEntry<>(EXECUTE_SCRIPT, payload)); + } + public static T execute(ExecutesMethod executesMethod, String command) { return handleResponse(executesMethod.execute(command)); } diff --git a/src/main/java/io/appium/java_client/InteractsWithApps.java b/src/main/java/io/appium/java_client/InteractsWithApps.java index eb73e6e30..fc5e17ada 100644 --- a/src/main/java/io/appium/java_client/InteractsWithApps.java +++ b/src/main/java/io/appium/java_client/InteractsWithApps.java @@ -20,21 +20,17 @@ import io.appium.java_client.appmanagement.ApplicationState; import io.appium.java_client.appmanagement.BaseActivateApplicationOptions; import io.appium.java_client.appmanagement.BaseInstallApplicationOptions; +import io.appium.java_client.appmanagement.BaseOptions; import io.appium.java_client.appmanagement.BaseRemoveApplicationOptions; import io.appium.java_client.appmanagement.BaseTerminateApplicationOptions; import javax.annotation.Nullable; import java.time.Duration; -import java.util.AbstractMap; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; -import static io.appium.java_client.MobileCommand.ACTIVATE_APP; -import static io.appium.java_client.MobileCommand.INSTALL_APP; -import static io.appium.java_client.MobileCommand.IS_APP_INSTALLED; -import static io.appium.java_client.MobileCommand.QUERY_APP_STATE; -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.TERMINATE_APP; -import static io.appium.java_client.MobileCommand.prepareArguments; @SuppressWarnings("rawtypes") public interface InteractsWithApps extends ExecutesMethod { @@ -56,12 +52,11 @@ default void installApp(String appPath) { * the particular platform. */ default void installApp(String appPath, @Nullable BaseInstallApplicationOptions options) { - String[] parameters = options == null ? new String[]{"appPath"} : - new String[]{"appPath", "options"}; - Object[] values = options == null ? new Object[]{appPath} : - new Object[]{appPath, options.build()}; - CommandExecutionHelper.execute(this, - new AbstractMap.SimpleEntry<>(INSTALL_APP, prepareArguments(parameters, values))); + Map args = new HashMap<>(); + args.put("app", appPath); + args.put("appPath", appPath); + Optional.ofNullable(options).map(BaseOptions::build).ifPresent(args::putAll); + CommandExecutionHelper.executeScript(this, "mobile: installApp", args); } /** @@ -71,8 +66,10 @@ default void installApp(String appPath, @Nullable BaseInstallApplicationOptions * @return True if app is installed, false otherwise. */ default boolean isAppInstalled(String bundleId) { - return CommandExecutionHelper.execute(this, - new AbstractMap.SimpleEntry<>(IS_APP_INSTALLED, prepareArguments("bundleId", bundleId))); + return CommandExecutionHelper.executeScript(this, "mobile: isAppInstalled", ImmutableMap.of( + "bundleId", bundleId, + "appId", bundleId + )); } /** @@ -106,12 +103,11 @@ default boolean removeApp(String bundleId) { * @return true if the uninstall was successful. */ default boolean removeApp(String bundleId, @Nullable BaseRemoveApplicationOptions options) { - String[] parameters = options == null ? new String[]{"bundleId"} : - new String[]{"bundleId", "options"}; - Object[] values = options == null ? new Object[]{bundleId} : - new Object[]{bundleId, options.build()}; - return CommandExecutionHelper.execute(this, - new AbstractMap.SimpleEntry<>(REMOVE_APP, prepareArguments(parameters, values))); + Map args = new HashMap<>(); + args.put("bundleId", bundleId); + args.put("appId", bundleId); + Optional.ofNullable(options).map(BaseOptions::build).ifPresent(args::putAll); + return CommandExecutionHelper.executeScript(this, "mobile: removeApp", args); } /** @@ -133,12 +129,11 @@ default void activateApp(String bundleId) { * particular platform. */ default void activateApp(String bundleId, @Nullable BaseActivateApplicationOptions options) { - String[] parameters = options == null ? new String[]{"bundleId"} : - new String[]{"bundleId", "options"}; - Object[] values = options == null ? new Object[]{bundleId} : - new Object[]{bundleId, options.build()}; - CommandExecutionHelper.execute(this, - new AbstractMap.SimpleEntry<>(ACTIVATE_APP, prepareArguments(parameters, values))); + Map args = new HashMap<>(); + args.put("bundleId", bundleId); + args.put("appId", bundleId); + Optional.ofNullable(options).map(BaseOptions::build).ifPresent(args::putAll); + CommandExecutionHelper.executeScript(this, "mobile: activateApp", args); } /** @@ -148,8 +143,12 @@ default void activateApp(String bundleId, @Nullable BaseActivateApplicationOptio * @return one of possible {@link ApplicationState} values, */ default ApplicationState queryAppState(String bundleId) { - return ApplicationState.ofCode(CommandExecutionHelper.execute(this, - new AbstractMap.SimpleEntry<>(QUERY_APP_STATE, ImmutableMap.of("bundleId", bundleId)))); + return ApplicationState.ofCode( + CommandExecutionHelper.executeScript(this, "mobile: queryAppState", ImmutableMap.of( + "bundleId", bundleId, + "appId", bundleId + )) + ); } /** @@ -171,11 +170,10 @@ default boolean terminateApp(String bundleId) { * @return true if the app was running before and has been successfully stopped. */ default boolean terminateApp(String bundleId, @Nullable BaseTerminateApplicationOptions options) { - String[] parameters = options == null ? new String[]{"bundleId"} : - new String[]{"bundleId", "options"}; - Object[] values = options == null ? new Object[]{bundleId} : - new Object[]{bundleId, options.build()}; - return CommandExecutionHelper.execute(this, - new AbstractMap.SimpleEntry<>(TERMINATE_APP, prepareArguments(parameters, values))); + Map args = new HashMap<>(); + args.put("bundleId", bundleId); + args.put("appId", bundleId); + Optional.ofNullable(options).map(BaseOptions::build).ifPresent(args::putAll); + return CommandExecutionHelper.executeScript(this, "mobile: terminateApp", args); } } diff --git a/src/main/java/io/appium/java_client/MobileCommand.java b/src/main/java/io/appium/java_client/MobileCommand.java index f5e9c7fb1..dbcab47b2 100644 --- a/src/main/java/io/appium/java_client/MobileCommand.java +++ b/src/main/java/io/appium/java_client/MobileCommand.java @@ -35,83 +35,144 @@ /** * The repository of mobile commands defined in the Mobile JSON * wire protocol. + * + * Most of these commands are platform-specific obsolete things and should eventually be replaced with + * calls to corresponding `mobile:` extensions, so we don't abuse non-w3c APIs */ public class MobileCommand { //General + @Deprecated protected static final String RESET; + @Deprecated protected static final String GET_STRINGS; + @Deprecated public static final String SET_VALUE; + @Deprecated protected static final String PULL_FILE; + @Deprecated protected static final String PULL_FOLDER; public static final String RUN_APP_IN_BACKGROUND; + @Deprecated protected static final String PERFORM_TOUCH_ACTION; + @Deprecated protected static final String PERFORM_MULTI_TOUCH; + @Deprecated public static final String LAUNCH_APP; + @Deprecated public static final String CLOSE_APP; + @Deprecated protected static final String GET_DEVICE_TIME; + @Deprecated protected static final String GET_SESSION; protected static final String LOG_EVENT; protected static final String GET_EVENTS; //region Applications Management + @Deprecated protected static final String IS_APP_INSTALLED; + @Deprecated protected static final String INSTALL_APP; + @Deprecated protected static final String ACTIVATE_APP; + @Deprecated protected static final String QUERY_APP_STATE; + @Deprecated protected static final String TERMINATE_APP; + @Deprecated protected static final String REMOVE_APP; //endregion //region Clipboard + @Deprecated public static final String GET_CLIPBOARD; + @Deprecated public static final String SET_CLIPBOARD; //endregion + @Deprecated protected static final String GET_PERFORMANCE_DATA; + @Deprecated protected static final String GET_SUPPORTED_PERFORMANCE_DATA_TYPES; + @Deprecated public static final String START_RECORDING_SCREEN; + @Deprecated public static final String STOP_RECORDING_SCREEN; + @Deprecated protected static final String HIDE_KEYBOARD; + @Deprecated protected static final String LOCK; //iOS + @Deprecated protected static final String SHAKE; + @Deprecated protected static final String TOUCH_ID; + @Deprecated protected static final String TOUCH_ID_ENROLLMENT; //Android + @Deprecated protected static final String CURRENT_ACTIVITY; + @Deprecated protected static final String END_TEST_COVERAGE; + @Deprecated protected static final String GET_DISPLAY_DENSITY; + @Deprecated protected static final String GET_NETWORK_CONNECTION; + @Deprecated protected static final String GET_SYSTEM_BARS; + @Deprecated protected static final String IS_KEYBOARD_SHOWN; + @Deprecated protected static final String IS_LOCKED; + @Deprecated public static final String LONG_PRESS_KEY_CODE; + @Deprecated protected static final String FINGER_PRINT; + @Deprecated protected static final String OPEN_NOTIFICATIONS; + @Deprecated public static final String PRESS_KEY_CODE; + @Deprecated protected static final String PUSH_FILE; + @Deprecated protected static final String SET_NETWORK_CONNECTION; + @Deprecated protected static final String START_ACTIVITY; + @Deprecated protected static final String TOGGLE_LOCATION_SERVICES; + @Deprecated protected static final String UNLOCK; + @Deprecated public static final String REPLACE_VALUE; protected static final String GET_SETTINGS; + @Deprecated protected static final String SET_SETTINGS; + @Deprecated protected static final String GET_CURRENT_PACKAGE; + @Deprecated protected static final String SEND_SMS; + @Deprecated protected static final String GSM_CALL; + @Deprecated protected static final String GSM_SIGNAL; + @Deprecated protected static final String GSM_VOICE; + @Deprecated protected static final String NETWORK_SPEED; + @Deprecated protected static final String POWER_CAPACITY; + @Deprecated protected static final String POWER_AC_STATE; + @Deprecated protected static final String TOGGLE_WIFI; + @Deprecated protected static final String TOGGLE_AIRPLANE_MODE; + @Deprecated protected static final String TOGGLE_DATA; protected static final String COMPARE_IMAGES; protected static final String EXECUTE_DRIVER_SCRIPT; + @Deprecated protected static final String GET_ALLSESSION; protected static final String EXECUTE_GOOGLE_CDP_COMMAND; From fa4f6f533429cc19aed8ad6f549333923eeec90d Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Thu, 13 Apr 2023 22:31:20 +0200 Subject: [PATCH 2/3] update checkstyle --- .../java_client/CommandExecutionHelper.java | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/java/io/appium/java_client/CommandExecutionHelper.java b/src/main/java/io/appium/java_client/CommandExecutionHelper.java index 98532c389..f2b920b03 100644 --- a/src/main/java/io/appium/java_client/CommandExecutionHelper.java +++ b/src/main/java/io/appium/java_client/CommandExecutionHelper.java @@ -33,10 +33,29 @@ public static T execute(ExecutesMethod executesMethod, return handleResponse(executesMethod.execute(keyValuePair.getKey(), keyValuePair.getValue())); } + public static T execute(ExecutesMethod executesMethod, String command) { + return handleResponse(executesMethod.execute(command)); + } + + private static T handleResponse(Response response) { + if (response != null) { + return (T) response.getValue(); + } + return null; + } + public static T executeScript(ExecutesMethod executesMethod, String scriptName) { return executeScript(executesMethod, scriptName, null); } + /** + * Simplifies arguments preparation for the script execution command. + * + * @param executesMethod Method executor instance. + * @param scriptName Extension script name. + * @param args Extension script arguments (if present). + * @return Script execution result. + */ public static T executeScript( ExecutesMethod executesMethod, String scriptName, @Nullable Map args ) { @@ -47,15 +66,4 @@ public static T executeScript( } return CommandExecutionHelper.execute(executesMethod, new AbstractMap.SimpleEntry<>(EXECUTE_SCRIPT, payload)); } - - public static T execute(ExecutesMethod executesMethod, String command) { - return handleResponse(executesMethod.execute(command)); - } - - private static T handleResponse(Response response) { - if (response != null) { - return (T) response.getValue(); - } - return null; - } } From 469dddb169a1ef728bc1d9a0b671237aed8bf29c Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Thu, 13 Apr 2023 22:32:20 +0200 Subject: [PATCH 3/3] Remove extra prefix --- src/main/java/io/appium/java_client/CommandExecutionHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/appium/java_client/CommandExecutionHelper.java b/src/main/java/io/appium/java_client/CommandExecutionHelper.java index f2b920b03..5290f319a 100644 --- a/src/main/java/io/appium/java_client/CommandExecutionHelper.java +++ b/src/main/java/io/appium/java_client/CommandExecutionHelper.java @@ -64,6 +64,6 @@ public static T executeScript( if (args != null) { payload.put("args", args.isEmpty() ? Collections.emptyList() : Collections.singletonList(args)); } - return CommandExecutionHelper.execute(executesMethod, new AbstractMap.SimpleEntry<>(EXECUTE_SCRIPT, payload)); + return execute(executesMethod, new AbstractMap.SimpleEntry<>(EXECUTE_SCRIPT, payload)); } }