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..336c09797 --- /dev/null +++ b/src/main/java/io/appium/java_client/Location.java @@ -0,0 +1,58 @@ +/* + * 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.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +import javax.annotation.Nullable; + +/** + * Represents the physical location. + */ +@Getter +@ToString +@EqualsAndHashCode +public class Location { + private final double latitude; + private final double longitude; + @Nullable 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..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,7 +251,16 @@ 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() { 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..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,7 +279,16 @@ 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() { 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..504f418b6 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,80 @@ 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; 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 { + + /** + * 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(); + + /** + * 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()} + * instead. + */ + @Deprecated(forRemoval = true) default Location location() { return getLocationContext().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 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 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 + * {@link #setLocation(io.appium.java_client.Location)} instead. + */ + @Deprecated(forRemoval = true) default void setLocation(Location location) { getLocationContext().setLocation(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", locationParameters)); + } }