From 5f36e288c2a7ff6f29ff6bcc2e9c2624053350db Mon Sep 17 00:00:00 2001 From: Valery Yatsynovich Date: Sun, 14 Jan 2024 19:44:57 +0200 Subject: [PATCH 1/3] chore: Add non-W3C Location-management endpoints deprecated in Selenium client --- .../io/appium/java_client/AppiumDriver.java | 1 + .../java/io/appium/java_client/Location.java | 56 +++++++++++++++++++ .../io/appium/java_client/MobileCommand.java | 6 ++ .../java_client/android/AndroidDriver.java | 1 + .../SupportsExtendedGeolocationCommands.java | 4 +- .../io/appium/java_client/ios/IOSDriver.java | 1 + .../java_client/remote/SupportsLocation.java | 55 +++++++++++++++++- 7 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 src/main/java/io/appium/java_client/Location.java diff --git a/src/main/java/io/appium/java_client/AppiumDriver.java b/src/main/java/io/appium/java_client/AppiumDriver.java index f4721dbf5..6d66639c9 100644 --- a/src/main/java/io/appium/java_client/AppiumDriver.java +++ b/src/main/java/io/appium/java_client/AppiumDriver.java @@ -73,6 +73,7 @@ public class AppiumDriver extends RemoteWebDriver implements // frequently used command parameters @Getter private final URL remoteAddress; + @Deprecated(forRemoval = true) protected final RemoteLocationContext locationContext; private final ExecuteMethod executeMethod; private final Set absentExtensionNames = new HashSet<>(); diff --git a/src/main/java/io/appium/java_client/Location.java b/src/main/java/io/appium/java_client/Location.java new file mode 100644 index 000000000..8f2dd16ec --- /dev/null +++ b/src/main/java/io/appium/java_client/Location.java @@ -0,0 +1,56 @@ +/* + * 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 lombok.Getter; +import lombok.ToString; + +import javax.annotation.Nullable; + +/** + * Represents the physical location. + */ +@Getter +@ToString +public class Location { + private final double latitude; + private final double longitude; + private final Double altitude; + + /** + * Create {@link Location} with latitude, longitude and altitude values. + * + * @param latitude latitude value. + * @param longitude longitude value. + * @param altitude altitude value (can be null). + */ + public Location(double latitude, double longitude, @Nullable Double altitude) { + this.latitude = latitude; + this.longitude = longitude; + this.altitude = altitude; + } + + /** + * Create {@link Location} with latitude and longitude values. + * + * @param latitude latitude value. + * @param longitude longitude value. + */ + public Location(double latitude, double longitude) { + this(latitude, longitude, null); + } +} diff --git a/src/main/java/io/appium/java_client/MobileCommand.java b/src/main/java/io/appium/java_client/MobileCommand.java index 15704ec40..6f7eafb34 100644 --- a/src/main/java/io/appium/java_client/MobileCommand.java +++ b/src/main/java/io/appium/java_client/MobileCommand.java @@ -187,6 +187,9 @@ public class MobileCommand { public static final String GET_CURRENT_CONTEXT_HANDLE = "getCurrentContextHandle"; public static final String SWITCH_TO_CONTEXT = "switchToContext"; + public static final String GET_LOCATION = "getLocation"; + public static final String SET_LOCATION = "setLocation"; + public static final Map commandRepository; static { @@ -365,6 +368,9 @@ public class MobileCommand { commandRepository.put(GET_CONTEXT_HANDLES, getC("/session/:sessionId/contexts")); commandRepository.put(GET_CURRENT_CONTEXT_HANDLE, getC("/session/:sessionId/context")); commandRepository.put(SWITCH_TO_CONTEXT, postC("/session/:sessionId/context")); + + commandRepository.put(GET_LOCATION, getC("/session/:sessionId/location")); + commandRepository.put(SET_LOCATION, postC("/session/:sessionId/location")); } /** 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 584dde1a7..d9f90d8ae 100644 --- a/src/main/java/io/appium/java_client/android/AndroidDriver.java +++ b/src/main/java/io/appium/java_client/android/AndroidDriver.java @@ -252,6 +252,7 @@ public AndroidBatteryInfo getBatteryInfo() { } @Override + @Deprecated(forRemoval = true) public RemoteLocationContext getLocationContext() { return locationContext; } diff --git a/src/main/java/io/appium/java_client/android/geolocation/SupportsExtendedGeolocationCommands.java b/src/main/java/io/appium/java_client/android/geolocation/SupportsExtendedGeolocationCommands.java index d1ccf8e2c..0472a5bab 100644 --- a/src/main/java/io/appium/java_client/android/geolocation/SupportsExtendedGeolocationCommands.java +++ b/src/main/java/io/appium/java_client/android/geolocation/SupportsExtendedGeolocationCommands.java @@ -18,7 +18,7 @@ import io.appium.java_client.CommandExecutionHelper; import io.appium.java_client.ExecutesMethod; -import org.openqa.selenium.remote.DriverCommand; +import io.appium.java_client.MobileCommand; import java.util.Map; @@ -31,7 +31,7 @@ public interface SupportsExtendedGeolocationCommands extends ExecutesMethod { * @param location The location object to set. */ default void setLocation(AndroidGeoLocation location) { - CommandExecutionHelper.execute(this, Map.entry(DriverCommand.SET_LOCATION, + CommandExecutionHelper.execute(this, Map.entry(MobileCommand.SET_LOCATION, Map.of("location", location.build()) )); } 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 995c196a6..cb80ac882 100644 --- a/src/main/java/io/appium/java_client/ios/IOSDriver.java +++ b/src/main/java/io/appium/java_client/ios/IOSDriver.java @@ -280,6 +280,7 @@ class IOSAlert implements Alert { } @Override + @Deprecated(forRemoval = true) public RemoteLocationContext getLocationContext() { return locationContext; } diff --git a/src/main/java/io/appium/java_client/remote/SupportsLocation.java b/src/main/java/io/appium/java_client/remote/SupportsLocation.java index b2211dfda..ddb48d458 100644 --- a/src/main/java/io/appium/java_client/remote/SupportsLocation.java +++ b/src/main/java/io/appium/java_client/remote/SupportsLocation.java @@ -16,19 +16,70 @@ package io.appium.java_client.remote; +import io.appium.java_client.CommandExecutionHelper; +import io.appium.java_client.ExecutesMethod; +import io.appium.java_client.MobileCommand; import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebDriverException; import org.openqa.selenium.html5.Location; import org.openqa.selenium.html5.LocationContext; import org.openqa.selenium.remote.html5.RemoteLocationContext; -public interface SupportsLocation extends WebDriver, LocationContext { - public RemoteLocationContext getLocationContext(); +import java.util.Map; +import java.util.Optional; +public interface SupportsLocation extends WebDriver, ExecutesMethod, LocationContext { + + @Deprecated(forRemoval = true) + RemoteLocationContext getLocationContext(); + + /** + * Gets the physical location of the browser. + * + * @return A {@link Location} containing the location information. Returns null if the location is not available + * @deprecated This method and whole {@link LocationContext} interface are deprecated, use {@link #getLocation()} + * instead. + */ + @Deprecated(forRemoval = true) default Location location() { return getLocationContext().location(); } + /** + * Gets the physical location. + * + * @return A {@link Location} containing the location information. Throws {@link WebDriverException} if the + * location is not available. + */ + default io.appium.java_client.Location getLocation() { + Map result = CommandExecutionHelper.execute(this, MobileCommand.GET_LOCATION); + return Optional.ofNullable(result).map(r -> + new io.appium.java_client.Location( + r.get("latitude").doubleValue(), + r.get("longitude").doubleValue(), + Optional.ofNullable(r.get("altitude")).map(Number::doubleValue).orElse(null) + ) + ).orElseThrow(() -> new WebDriverException("Cannot retrieve location")); + } + + /** + * Sets the physical location. + * + * @param location A {@link Location} containing the new location information. + * @deprecated This method and whole {@link LocationContext} interface are deprecated, use + * {@link #setLocation(io.appium.java_client.Location)} instead. + */ + @Deprecated(forRemoval = true) default void setLocation(Location location) { getLocationContext().setLocation(location); } + + /** + * Sets the physical location. + * + * @param location A {@link Location} containing the new location information. + */ + default void setLocation(io.appium.java_client.Location location) { + execute(MobileCommand.SET_LOCATION, Map.of("location", location)); + } } From c77d068282f0007e95dd723d7cd159ecd3f2230b Mon Sep 17 00:00:00 2001 From: Valery Yatsynovich Date: Mon, 15 Jan 2024 12:18:53 +0200 Subject: [PATCH 2/3] address comments --- .../java/io/appium/java_client/Location.java | 4 ++- .../java_client/remote/SupportsLocation.java | 25 +++++++++++-------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/main/java/io/appium/java_client/Location.java b/src/main/java/io/appium/java_client/Location.java index 8f2dd16ec..336c09797 100644 --- a/src/main/java/io/appium/java_client/Location.java +++ b/src/main/java/io/appium/java_client/Location.java @@ -16,6 +16,7 @@ package io.appium.java_client; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; @@ -26,10 +27,11 @@ */ @Getter @ToString +@EqualsAndHashCode public class Location { private final double latitude; private final double longitude; - private final Double altitude; + @Nullable private final Double altitude; /** * Create {@link Location} with latitude, longitude and altitude values. diff --git a/src/main/java/io/appium/java_client/remote/SupportsLocation.java b/src/main/java/io/appium/java_client/remote/SupportsLocation.java index ddb48d458..a240ccbca 100644 --- a/src/main/java/io/appium/java_client/remote/SupportsLocation.java +++ b/src/main/java/io/appium/java_client/remote/SupportsLocation.java @@ -16,6 +16,7 @@ package io.appium.java_client.remote; +import com.google.common.collect.ImmutableMap; import io.appium.java_client.CommandExecutionHelper; import io.appium.java_client.ExecutesMethod; import io.appium.java_client.MobileCommand; @@ -34,7 +35,7 @@ public interface SupportsLocation extends WebDriver, ExecutesMethod, LocationCon RemoteLocationContext getLocationContext(); /** - * Gets the physical location of the browser. + * Gets the current device's geolocation coordinates. * * @return A {@link Location} containing the location information. Returns null if the location is not available * @deprecated This method and whole {@link LocationContext} interface are deprecated, use {@link #getLocation()} @@ -46,24 +47,22 @@ default Location location() { } /** - * Gets the physical location. + * Gets the current device's geolocation coordinates. * * @return A {@link Location} containing the location information. Throws {@link WebDriverException} if the * location is not available. */ default io.appium.java_client.Location getLocation() { Map result = CommandExecutionHelper.execute(this, MobileCommand.GET_LOCATION); - return Optional.ofNullable(result).map(r -> - new io.appium.java_client.Location( - r.get("latitude").doubleValue(), - r.get("longitude").doubleValue(), - Optional.ofNullable(r.get("altitude")).map(Number::doubleValue).orElse(null) - ) - ).orElseThrow(() -> new WebDriverException("Cannot retrieve location")); + return new io.appium.java_client.Location( + result.get("latitude").doubleValue(), + result.get("longitude").doubleValue(), + Optional.ofNullable(result.get("altitude")).map(Number::doubleValue).orElse(null) + ); } /** - * Sets the physical location. + * Sets the current device's geolocation coordinates. * * @param location A {@link Location} containing the new location information. * @deprecated This method and whole {@link LocationContext} interface are deprecated, use @@ -75,11 +74,15 @@ default void setLocation(Location location) { } /** - * Sets the physical location. + * Sets the current device's geolocation coordinates. * * @param location A {@link Location} containing the new location information. */ default void setLocation(io.appium.java_client.Location location) { + ImmutableMap.Builder locationParameters = ImmutableMap.builder(); + locationParameters.put("latitude", location.getLatitude()); + locationParameters.put("longitude", location.getLongitude()); + Optional.ofNullable(location.getAltitude()).ifPresent(altitude -> locationParameters.put("altitude", altitude)); execute(MobileCommand.SET_LOCATION, Map.of("location", location)); } } From 17507330c7cda3bd2619690db43869e9908733e9 Mon Sep 17 00:00:00 2001 From: Valery Yatsynovich Date: Mon, 15 Jan 2024 20:22:05 +0200 Subject: [PATCH 3/3] address comments --- .../io/appium/java_client/android/AndroidDriver.java | 8 ++++++++ src/main/java/io/appium/java_client/ios/IOSDriver.java | 8 ++++++++ .../io/appium/java_client/remote/SupportsLocation.java | 9 ++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) 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 d9f90d8ae..dfd9a879a 100644 --- a/src/main/java/io/appium/java_client/android/AndroidDriver.java +++ b/src/main/java/io/appium/java_client/android/AndroidDriver.java @@ -251,6 +251,14 @@ public AndroidBatteryInfo getBatteryInfo() { return new AndroidBatteryInfo(CommandExecutionHelper.executeScript(this, "mobile: batteryInfo")); } + /** + * Provides the location context. + * + * @return instance of {@link RemoteLocationContext} + * @deprecated This method, {@link org.openqa.selenium.html5.LocationContext} and {@link RemoteLocationContext} + * interface are deprecated, use {@link #getLocation()} and + * {@link #setLocation(io.appium.java_client.Location)} instead. + */ @Override @Deprecated(forRemoval = true) public RemoteLocationContext getLocationContext() { 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 cb80ac882..6cc48469e 100644 --- a/src/main/java/io/appium/java_client/ios/IOSDriver.java +++ b/src/main/java/io/appium/java_client/ios/IOSDriver.java @@ -279,6 +279,14 @@ class IOSAlert implements Alert { } + /** + * Provides the location context. + * + * @return instance of {@link RemoteLocationContext} + * @deprecated This method, {@link org.openqa.selenium.html5.LocationContext} and {@link RemoteLocationContext} + * interface are deprecated, use {@link #getLocation()} and + * {@link #setLocation(io.appium.java_client.Location)} instead. + */ @Override @Deprecated(forRemoval = true) public RemoteLocationContext getLocationContext() { diff --git a/src/main/java/io/appium/java_client/remote/SupportsLocation.java b/src/main/java/io/appium/java_client/remote/SupportsLocation.java index a240ccbca..504f418b6 100644 --- a/src/main/java/io/appium/java_client/remote/SupportsLocation.java +++ b/src/main/java/io/appium/java_client/remote/SupportsLocation.java @@ -31,6 +31,13 @@ public interface SupportsLocation extends WebDriver, ExecutesMethod, LocationContext { + /** + * Provides the location context. + * + * @return instance of {@link RemoteLocationContext} + * @deprecated This method, {@link LocationContext} and {@link RemoteLocationContext} interface are deprecated, use + * {@link #getLocation()} and {@link #setLocation(io.appium.java_client.Location)} instead. + */ @Deprecated(forRemoval = true) RemoteLocationContext getLocationContext(); @@ -83,6 +90,6 @@ default void setLocation(io.appium.java_client.Location location) { locationParameters.put("latitude", location.getLatitude()); locationParameters.put("longitude", location.getLongitude()); Optional.ofNullable(location.getAltitude()).ifPresent(altitude -> locationParameters.put("altitude", altitude)); - execute(MobileCommand.SET_LOCATION, Map.of("location", location)); + execute(MobileCommand.SET_LOCATION, Map.of("location", locationParameters)); } }