From 42fd43299473701ada7c99528c1c323917f804d9 Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Fri, 10 May 2019 14:11:05 +0200 Subject: [PATCH] Add gesture support --- src/Quamotion.Malaga/TouchAction.cs | 217 +++++++++++++++++++++ src/Quamotion.Malaga/TouchOperation.cs | 47 +++++ src/Quamotion.Malaga/WdaCommandExecutor.cs | 4 + src/Quamotion.Malaga/WdaDriver.cs | 98 ++++++++++ src/Quamotion.Malaga/WdaDriverCommand.cs | 5 +- 5 files changed, 370 insertions(+), 1 deletion(-) create mode 100644 src/Quamotion.Malaga/TouchAction.cs create mode 100644 src/Quamotion.Malaga/TouchOperation.cs diff --git a/src/Quamotion.Malaga/TouchAction.cs b/src/Quamotion.Malaga/TouchAction.cs new file mode 100644 index 0000000..78acfa3 --- /dev/null +++ b/src/Quamotion.Malaga/TouchAction.cs @@ -0,0 +1,217 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Quamotion.Malaga +{ /// + /// Represents a touch action which can be executed using the WebDriverAgent. + /// + public class TouchAction + { + /// + /// Gets the operation being executed. + /// + [JsonConverter(typeof(StringEnumConverter), /* camelCaseText */ true)] + [JsonProperty("action")] + public TouchOperation Action { get; private set; } + + /// + /// Gets a dictionary which contains the options for this operation. + /// + [JsonProperty("options")] + public Dictionary Options { get; private set; } = new Dictionary(); + + /// + /// Performs a tap (finger down and finger up) operation. + /// + /// + /// The x-coordinate of the position at which to tap. + /// + /// + /// The y-coordinate of the position at which to tap. + /// + /// + /// The number of taps to perform. + /// + /// + /// A which represents the tap operation. + /// + public static TouchAction Tap(double x, double y, int count = 1) + { + return new TouchAction() + { + Action = TouchOperation.Tap, + Options = new Dictionary() + { + { nameof(x), x }, + { nameof(y), y }, + { nameof(count), count } + } + }; + } + + /// + /// Performs a long press operation. + /// + /// + /// The x-coordinate of the position at which to tap. + /// + /// + /// The y-coordinate of the position at which to tap. + /// + /// + /// The duration, in milliseconds, of the tap gesture. + /// + /// + /// The amount of pressure to apply. + /// + /// + /// A which represents the long press operation. + /// + public static TouchAction LongPress(double x, double y, double duration = 500, double pressure = 0) + { + return new TouchAction() + { + Action = TouchOperation.LongPress, + Options = new Dictionary() + { + { nameof(x), x }, + { nameof(y), y }, + { nameof(duration), duration }, + { nameof(pressure), pressure } + } + }; + } + + /// + /// Performs a finger down operation. + /// + /// + /// The x-coordinate of the position at which to perform the finger down. + /// + /// + /// The y-coordinate of the position at which to perform the finger down. + /// + /// + /// The amount of pressure to apply. + /// + /// + /// A which represents the finger down operation. + /// + public static TouchAction Press(double x, double y, double pressure = 0) + { + return new TouchAction() + { + Action = TouchOperation.Press, + Options = new Dictionary() + { + { nameof(x), x }, + { nameof(y), y }, + { nameof(pressure), pressure } + } + }; + } + + /// + /// Performs a finger up operation. + /// + /// + /// A which represents the finger up operation. + /// + public static TouchAction Release() + { + return new TouchAction() + { + Action = TouchOperation.Release, + Options = new Dictionary() + { + } + }; + } + + /// + /// Moves the finger to a new position. + /// + /// + /// The x-coordiante of the position to which to move the finger. + /// + /// + /// The y-coordinate of the position to which to move the finger. + /// + /// + /// A which represents the move operation. + /// + public static TouchAction MoveTo(double x, double y) + { + return new TouchAction() + { + Action = TouchOperation.MoveTo, + Options = new Dictionary() + { + { nameof(x), x }, + { nameof(y), y }, + } + }; + } + + /// + /// Waits for a specific amount of time. + /// + /// + /// The amount of time to wait. + /// + /// + /// A which represents the wait operation. + /// + public static TouchAction Wait(TimeSpan timeSpan) + { + return Wait(timeSpan.TotalMilliseconds); + } + + /// + /// Waits for a specific amount of time. + /// + /// + /// The amount of time to wait, in milliseconds. + /// + /// + /// A which represents the wait operation. + /// + public static TouchAction Wait(double ms) + { + return new TouchAction() + { + Action = TouchOperation.Wait, + Options = new Dictionary() + { + { nameof(ms), ms }, + } + }; + } + + /// + /// Cancels the current operation. + /// + /// + /// A which represents the cancel operation. + /// + public static TouchAction Cancel() + { + return new TouchAction() + { + Action = TouchOperation.Cancel, + Options = new Dictionary() + { + } + }; + } + + /// + public override string ToString() + { + return this.Action.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Quamotion.Malaga/TouchOperation.cs b/src/Quamotion.Malaga/TouchOperation.cs new file mode 100644 index 0000000..70f2823 --- /dev/null +++ b/src/Quamotion.Malaga/TouchOperation.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Quamotion.Malaga +{ + /// + /// Represents a touch operation. + /// + public enum TouchOperation + { + /// + /// Performs a single tap. + /// + Tap, + + /// + /// Performs a finger down and wait operation. + /// + LongPress, + + /// + /// Performs a finger down operation. + /// + Press, + + /// + /// Performs a finger up operation. + /// + Release, + + /// + /// Performs a finger move operation. + /// + MoveTo, + + /// + /// Performs a wait operation. + /// + Wait, + + /// + /// Cancels the current operation. + /// + Cancel + } +} diff --git a/src/Quamotion.Malaga/WdaCommandExecutor.cs b/src/Quamotion.Malaga/WdaCommandExecutor.cs index c5425d4..6694b91 100644 --- a/src/Quamotion.Malaga/WdaCommandExecutor.cs +++ b/src/Quamotion.Malaga/WdaCommandExecutor.cs @@ -29,6 +29,10 @@ public WdaCommandExecutor(Uri addressOfRemoteServer, string sessionId, TimeSpan this.CommandInfoRepository.TryAddCommand(WdaDriverCommand.Type, new CommandInfo(CommandInfo.PostCommand, "/session/{sessionId}/wda/keyboard/type")); this.CommandInfoRepository.TryAddCommand(WdaDriverCommand.PressDeviceButton, new CommandInfo(CommandInfo.PostCommand, "/session/{sessionId}/wda/pressDeviceButton")); + + this.CommandInfoRepository.TryAddCommand(WdaDriverCommand.TouchAndHold, new CommandInfo(CommandInfo.PostCommand, "/session/{sessionId}/wda/touchAndHold")); + this.CommandInfoRepository.TryAddCommand(WdaDriverCommand.Drag, new CommandInfo(CommandInfo.PostCommand, "/session/{sessionId}/wda/dragfromtoforduration")); + this.CommandInfoRepository.TryAddCommand(WdaDriverCommand.PerformTouch, new CommandInfo(CommandInfo.PostCommand, "/session/{sessionId}/wda/touch/perform")); } public override Response Execute(Command commandToExecute) diff --git a/src/Quamotion.Malaga/WdaDriver.cs b/src/Quamotion.Malaga/WdaDriver.cs index eb112dd..b3128ac 100644 --- a/src/Quamotion.Malaga/WdaDriver.cs +++ b/src/Quamotion.Malaga/WdaDriver.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Drawing; namespace Quamotion.Malaga { @@ -110,6 +111,103 @@ public virtual ScreenOrientation Rotation } } + /// + /// Sends a touch and hold event to the device. + /// + /// + /// The position at which to touch. + /// + /// + /// The duration of the touch event, in seconds. + /// + public virtual void TouchAndHold(PointF location, TimeSpan duration) + { + // TODO: find a way to handle the timeout + // var timeout = Math.Max(Timeouts.TestServerRequestTimeout.TotalSeconds, 2 * duration.TotalSeconds); + this.Execute( + WdaDriverCommand.TouchAndHold, + new Dictionary() + { + { "x", location.X }, + { "y", location.Y }, + { "duration", duration.TotalSeconds } + }); + } + + /// + /// Sends a drag gesture to the device. + /// + /// + /// The location at which the drag gesture begins. + /// + /// + /// The location at which the drag gesture ends. + /// + /// + /// The duration of the drag gesture. + /// + public virtual void Drag(PointF from, PointF to, TimeSpan duration) + { + // Drag on iOS is slow, _very_ slow. + // Increase the timeout to make sure we don't time out (which would be a TaskCancelledException) + // TODO: find a way to work with the timeout + // var timeout = Math.Max(Timeouts.TestServerRequestTimeout.TotalSeconds, 15 + (5 * duration.TotalSeconds)); + + this.Execute( + WdaDriverCommand.Drag, + new Dictionary() + { + + { "fromX", from.X }, + { "fromY", from.Y }, + { "toX", to.X }, + { "toY", to.Y }, + { "duration", duration.TotalSeconds } + }); + } + + /// + /// Performs a sequence of touch actions. + /// + /// + /// The touch actions to execute. + /// + /// + /// A which can be used to cancel the asynchronous operation. + /// + /// + /// A which represents the asynchronous operation. + /// + public virtual void PerformTouch(Collection touches) + { + double duration = 0; + + foreach (var touch in touches) + { + if (touch.Action == TouchOperation.Wait) + { + duration += (double)touch.Options["ms"]; + } + else if (touch.Action == TouchOperation.LongPress) + { + duration += (double)touch.Options["duration"]; + } + } + + // TODO: figure out a way to pass the timeout + // TimeSpan.FromMilliseconds(Timeouts.TestServerRequestTimeout.TotalMilliseconds + (2 * duration)), + + var json = JsonConvert.SerializeObject( + new + { + actions = touches + }); + + this.Execute( + WdaDriverCommand.PerformTouch + json); + } + /// /// Gets the text of the current alert. /// diff --git a/src/Quamotion.Malaga/WdaDriverCommand.cs b/src/Quamotion.Malaga/WdaDriverCommand.cs index 45f0a88..8010e4f 100644 --- a/src/Quamotion.Malaga/WdaDriverCommand.cs +++ b/src/Quamotion.Malaga/WdaDriverCommand.cs @@ -9,7 +9,6 @@ public static class WdaDriverCommand public const string GetOrientation = "getOrientation"; public const string SetOrientation = "setOrientation"; - public const string GetRotation = "getRotation"; public const string SetRotation = "setRotation"; @@ -21,5 +20,9 @@ public static class WdaDriverCommand public const string Type = "wdaType"; public const string PressDeviceButton = "deviceButton"; + + public const string TouchAndHold = "touchAndHold"; + public const string Drag = "drag"; + public const string PerformTouch = "performTouch"; } }