diff --git a/Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml b/Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml index 6b5932b4f1..e3b4544fee 100644 --- a/Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml +++ b/Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml @@ -3,7 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:UserControlsLib1="clr-namespace:Ginger.UserControlsLib" xmlns:Activities="clr-namespace:Ginger.Activities" + xmlns:UserControlsLib1="clr-namespace:Ginger.UserControlsLib" xmlns:Activities="clr-namespace:Ginger.Activities" xmlns:UserControls="clr-namespace:Ginger.UserControls" xmlns:Actions="clr-namespace:Ginger.Actions" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" @@ -15,9 +15,14 @@ - + + + + @@ -61,11 +66,6 @@ - - - + + + + + + + + diff --git a/Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs b/Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs index e6dce2c547..dcfd22514e 100644 --- a/Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs +++ b/Ginger/Ginger/Actions/ActionEditPages/ActMobileDeviceEditPage.xaml.cs @@ -28,6 +28,7 @@ limitations under the License. using System.Windows.Controls; using System.Windows.Controls.Primitives; + namespace Ginger.Actions { /// @@ -39,22 +40,25 @@ public partial class ActMobileDeviceEditPage : Page ActMobileDevice mAct; Context mContext; bool isValueExpression; + public ActMobileDeviceEditPage(ActMobileDevice Act) { InitializeComponent(); - + mAct = Act; mContext = Context.GetAsContext(Act.Context); - + BindControls(); SetControlsView(); } - + private void BindControls() { xOperationNameComboBox.Init(mAct, nameof(mAct.MobileDeviceAction), typeof(ActMobileDevice.eMobileDeviceAction), ActionNameComboBox_SelectionChanged); + + xInputVE.Init(Context.GetAsContext(mAct.Context), mAct.ActionInput, nameof(ActInputValue.Value)); xAuthResultComboBox.Init(mAct, nameof(mAct.AuthResultSimulation), typeof(ActMobileDevice.eAuthResultSimulation), AuthResultComboBox_SelectionChanged); @@ -66,7 +70,15 @@ private void BindControls() xX2TxtBox.Init(Context.GetAsContext(mAct.Context), mAct.X2, nameof(ActInputValue.Value)); xY2TxtBox.Init(Context.GetAsContext(mAct.Context), mAct.Y2, nameof(ActInputValue.Value)); - xPhotoSumilationTxtBox.Init(Context.GetAsContext(mAct.Context), mAct.GetOrCreateInputParam(nameof(ActMobileDevice.SimulatedPhotoPath)), true, true, UCValueExpression.eBrowserType.File, "*", ValueTextBox_ClickBrowse); + xPhotoSumilationTxtBox.Init(Context.GetAsContext(mAct.Context), mAct.GetOrCreateInputParam(nameof(ActMobileDevice.SimulatedPhotoPath)), true, true, UCValueExpression.eBrowserType.File, "*"); + + xDeviceRotateComboBox.Init(mAct, nameof(mAct.RotateDeviceState), typeof(ActMobileDevice.eRotateDeviceState), ActionNameComboBox_SelectionChanged); + + xDataTypeComboBox.Init(mAct, nameof(mAct.PerformanceTypes), typeof(ActMobileDevice.ePerformanceTypes), ActionNameComboBox_SelectionChanged); + + xFilePathTextBox.Init(Context.GetAsContext(mAct.Context), mAct.FilePathInput, nameof(ActInputValue.Value), true, true, UCValueExpression.eBrowserType.File, "*"); + + xFolderPathTxtBox.Init(Context.GetAsContext(mAct.Context), mAct.FolderPathInput, nameof(ActMobileDevice.Value), true, true, UCValueExpression.eBrowserType.Folder, "*"); xAppPackageVE.Init(Context.GetAsContext(mAct.Context), mAct.ActionAppPackage, nameof(ActInputValue.Value)); @@ -77,7 +89,6 @@ private void BindControls() UpdateBaseLineImage(true); - WeakEventManager.RemoveHandler(source: xPhotoSumilationTxtBox.ValueTextBox, eventName: nameof(UIElement.LostFocus), handler: ValueTextBox_LostFocus); WeakEventManager.AddHandler(source: xPhotoSumilationTxtBox.ValueTextBox, eventName: nameof(UIElement.LostFocus), handler: ValueTextBox_LostFocus); @@ -127,13 +138,14 @@ private void ValueTextBox_LostFocus(object sender, RoutedEventArgs e) { UpdateBaseLineImage(); } + - private void ValueTextBox_ClickBrowse(object sender, RoutedEventArgs e) + + private void BrowseButton_Click(object sender, RoutedEventArgs e) { string filePath = UpdateBaseLineImage(); ImportPhotoToSolutionFolder(filePath); } - private string UpdateBaseLineImage(bool firstTime = false) { string FileName = General.GetFullFilePath(xPhotoSumilationTxtBox.ValueTextBox.Text); @@ -210,7 +222,10 @@ private void SetControlsView() xDragPnl.Visibility = Visibility.Collapsed; xSwipePnl.Visibility = Visibility.Collapsed; xInputPnl.Visibility = Visibility.Collapsed; - + xFileTransferPnl.Visibility = Visibility.Collapsed; + xSpecificPerformanceDataPnl.Visibility = Visibility.Collapsed; + xDeviceRotationPnl.Visibility = Visibility.Collapsed; + switch (mAct.MobileDeviceAction) { case ActMobileDevice.eMobileDeviceAction.PressKey: @@ -260,15 +275,68 @@ private void SetControlsView() xAuthSimulationPnl.Visibility = Visibility.Visible; break; + case ActMobileDevice.eMobileDeviceAction.OpenDeeplink: + xAppPnl.Visibility = Visibility.Visible; + xInputLabelVE.Content = "Link:"; + xInputPnl.Visibility = Visibility.Visible; + break; + case ActMobileDevice.eMobileDeviceAction.CloseApp: case ActMobileDevice.eMobileDeviceAction.OpenApp: + case ActMobileDevice.eMobileDeviceAction.IsAppInstalled: + case ActMobileDevice.eMobileDeviceAction.RemoveApp: + case ActMobileDevice.eMobileDeviceAction.QueryAppState: xAppPnl.Visibility = Visibility.Visible; break; - + case ActMobileDevice.eMobileDeviceAction.SetContext: xInputLabelVE.Content = "Context to Set:"; xInputPnl.Visibility = Visibility.Visible; break; + + case ActMobileDevice.eMobileDeviceAction.RunScript: + xInputLabelVE.Content = "Script:"; + xInputPnl.Visibility = Visibility.Visible; + break; + + case ActMobileDevice.eMobileDeviceAction.StartRecordingScreen: + xInputLabelVE.Content = "Note: Max duration recording: 30 min."; + xInputVE.Visibility = Visibility.Collapsed; + xInputPnl.Visibility = Visibility.Visible; + break; + + case ActMobileDevice.eMobileDeviceAction.GetDeviceLogs: + case ActMobileDevice.eMobileDeviceAction.StopRecordingScreen: + xFilePathLbl.Visibility = Visibility.Collapsed; + xFilePathTextBox.Visibility = Visibility.Collapsed; + xFolderPathLbl.Content = "Save to Folder\\File:"; + xFileTransferPnl.Visibility = Visibility.Visible; + break; + + case ActMobileDevice.eMobileDeviceAction.PushFileToDevice: + xFilePathLbl.Content = "Local File to Push:"; + xFolderPathLbl.Content = "Device Target Folder:"; + xFileTransferPnl.Visibility = Visibility.Visible; + break; + + case ActMobileDevice.eMobileDeviceAction.PullFileFromDevice: + xFileTransferPnl.Visibility = Visibility.Visible; + break; + + case ActMobileDevice.eMobileDeviceAction.SetClipboardText: + xInputLabelVE.Content = "Text:"; + xInputPnl.Visibility = Visibility.Visible; + break; + + case ActMobileDevice.eMobileDeviceAction.GetSpecificPerformanceData: + xAppPnl.Visibility = Visibility.Visible; + xSpecificPerformanceDataPnl.Visibility = Visibility.Visible; + break; + + case ActMobileDevice.eMobileDeviceAction.RotateSimulation: + xDeviceRotationPnl.Visibility = Visibility.Visible; + break; + } } diff --git a/Ginger/Ginger/Drivers/DriversWindows/MobileDriverWindow.xaml.cs b/Ginger/Ginger/Drivers/DriversWindows/MobileDriverWindow.xaml.cs index 58f71fb087..89ed95fc97 100644 --- a/Ginger/Ginger/Drivers/DriversWindows/MobileDriverWindow.xaml.cs +++ b/Ginger/Ginger/Drivers/DriversWindows/MobileDriverWindow.xaml.cs @@ -39,6 +39,7 @@ limitations under the License. using System.Windows.Media; using System.Windows.Media.Imaging; + namespace Ginger.Drivers.DriversWindows { /// @@ -62,12 +63,13 @@ public partial class MobileDriverWindow : Window bool mWindowIsOpen = true; bool IsRecording = false; - ObservableList mDeviceDetails = []; + + ObservableList mDeviceDetails = []; public MobileDriverWindow(DriverBase driver, Agent agent) { InitializeComponent(); - + mDriver = (IMobileDriverWindow)driver; mAgent = agent; @@ -78,7 +80,7 @@ public MobileDriverWindow(DriverBase driver, Agent agent) SetDeviceDetailsGridView(); SetDeviceMetricsGridView(); } - + private async void RefreshDetailsTable(object sender, RoutedEventArgs e) { await this.Dispatcher.InvokeAsync(async () => @@ -201,7 +203,13 @@ private void RemoveRectangle() xHighlighterBorder.Height = 0; xHighlighterBorder.Visibility = Visibility.Collapsed; } - + public void UpdateRotateIcon() + { + Dispatcher.Invoke(() => + { + SetOrientationButton(); + }); + } public void UpdateRecordingImage(bool ShowRecordIcon) { Dispatcher.Invoke(() => @@ -267,15 +275,16 @@ await this.Dispatcher.InvokeAsync(async () => } break; + case DriverBase.eDriverMessageType.RotateEvent: + UpdateRotateIcon(); + break; + case DriverBase.eDriverMessageType.RecordingEvent: IsRecording = sender != null && (bool)sender; - UpdateRecordingImage(IsRecording); - break; case DriverBase.eDriverMessageType.HighlightElement: - if (sender is Amdocs.Ginger.Common.UIElement.ElementInfo) { HighlightElementEvent(sender as Amdocs.Ginger.Common.UIElement.ElementInfo); @@ -1323,6 +1332,7 @@ private void SetOrientationButton() } } + private void DoContinualDeviceScreenshotRefresh() { Task.Run(() => diff --git a/Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs b/Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs index a2d7683589..2203c8502c 100644 --- a/Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs +++ b/Ginger/GingerCoreNET/ActionsLib/UI/Mobile/ActMobileDevice.cs @@ -75,6 +75,32 @@ public eAuthResultSimulation AuthResultSimulation OnPropertyChanged(nameof(AuthResultSimulation)); } } + public eRotateDeviceState RotateDeviceState + { + get + { + return GetOrCreateInputParam(nameof(RotateDeviceState), eRotateDeviceState.Portrait); + } + set + { + AddOrUpdateInputParamValue(nameof(RotateDeviceState), value.ToString()); + OnPropertyChanged(nameof(RotateDeviceState)); + } + } + + public ePerformanceTypes PerformanceTypes + { + get + { + return GetOrCreateInputParam(nameof(PerformanceTypes), ePerformanceTypes.Batteryinfo); + } + set + { + AddOrUpdateInputParamValue(nameof(PerformanceTypes), value.ToString()); + OnPropertyChanged(nameof(PerformanceTypes)); + } + } + public eAuthResultDetailsFailureSimulation AuthResultDetailsFailureSimulation { @@ -114,6 +140,33 @@ public ePressKey MobilePressKey OnPropertyChanged(nameof(MobilePressKey)); } } + + + public ActInputValue FilePathInput + { + get + { + return GetOrCreateInputParam(nameof(FilePathInput)); + } + set + { + AddOrUpdateInputParamValue(nameof(FilePathInput), value.ToString()); + OnPropertyChanged(nameof(FilePathInput)); + } + } + + public ActInputValue FolderPathInput + { + get + { + return GetOrCreateInputParam(nameof(FolderPathInput)); + } + set + { + AddOrUpdateInputParamValue(nameof(FolderPathInput), value.ToString()); + OnPropertyChanged(nameof(FolderPathInput)); + } + } public ActInputValue X1 { @@ -192,7 +245,7 @@ public ActInputValue ActionInput OnPropertyChanged(nameof(ActionInput)); } } - + public ActInputValue PressDuration { get @@ -285,7 +338,29 @@ public enum eAuthResultSimulation [EnumValueDescription("Cancel")] Cancel } + public enum ePerformanceTypes + { + [EnumValueDescription("cpuinfo")] + Cpuinfo, + [EnumValueDescription("memoryinfo")] + Memoryinfo, + [EnumValueDescription("batteryinfo")] + Batteryinfo, + [EnumValueDescription("networkinfo")] + Networkinfo, + [EnumValueDescription("diskinfo")] + Diskinfo, + } + + + public enum eRotateDeviceState + { + [EnumValueDescription("Landscape")] + Landscape, + [EnumValueDescription("Portrait")] + Portrait + } public enum eAuthResultDetailsFailureSimulation { [EnumValueDescription("Not Recognized")] @@ -383,6 +458,40 @@ public enum eMobileDeviceAction GetAvailableContexts, [EnumValueDescription("Set Context")] SetContext, + [EnumValueDescription("Open Deep Link")] + OpenDeeplink, + [EnumValueDescription("Is Keyboard Visible")] + IsKeyboardVisible, + [EnumValueDescription("Is Device Locked")] + IsLocked, + [EnumValueDescription("Is App Installed")] + IsAppInstalled, + [EnumValueDescription("Remove App")] + RemoveApp, + [EnumValueDescription("Get App State")] + QueryAppState, + [EnumValueDescription("Simulate Device Rotation")] + RotateSimulation, + [EnumValueDescription("Run Script")] + RunScript, + [EnumValueDescription("Start Recording Screen")] + StartRecordingScreen, + [EnumValueDescription("Stop Recording Screen")] + StopRecordingScreen, + [EnumValueDescription("Hide Keyboard")] + HideKeyboard, + [EnumValueDescription("Push File to Device")] + PushFileToDevice, + [EnumValueDescription("Pull File From Device")] + PullFileFromDevice, + [EnumValueDescription("Set Clipboard Text")] + SetClipboardText, + [EnumValueDescription("Get Specific Performance Data")] + GetSpecificPerformanceData, + [EnumValueDescription("Get Device Logs")] + GetDeviceLogs, + [EnumValueDescription("Get Clipboard Text")] + GetClipboardText, } public enum ePressKey diff --git a/Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs b/Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs index 4dfca7c3e0..22ee13cb7d 100644 --- a/Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs +++ b/Ginger/GingerCoreNET/Drivers/CoreDrivers/Mobile/Appium/GenericAppiumDriver.cs @@ -53,6 +53,7 @@ limitations under the License. using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Android; +using OpenQA.Selenium.Appium.Enums; using OpenQA.Selenium.Appium.Interactions; using OpenQA.Selenium.Appium.iOS; using OpenQA.Selenium.Interactions; @@ -71,8 +72,6 @@ limitations under the License. using System.Xml; using AppiumInteractions = OpenQA.Selenium.Appium.Interactions; - - namespace Amdocs.Ginger.CoreNET { public class GenericAppiumDriver : DriverBase, IWindowExplorer, IRecord, IDriverWindow, IMobileDriverWindow, IVisualTestingDriver @@ -112,7 +111,7 @@ public string GetDriverWindowName(Agent.eDriverType driverSubType = Agent.eDrive [UserConfigured] [UserConfiguredDefault("Auto")] [UserConfiguredDescription("Define the Height to set for the mobile device screenshot")] - public String ScreenshotHeight { get; set;} + public String ScreenshotHeight { get; set; } [UserConfigured] [UserConfiguredDefault("Auto")] @@ -169,7 +168,7 @@ public string GetDriverWindowName(Agent.eDriverType driverSubType = Agent.eDrive public ObservableList AppiumCapabilities { get; set; } protected IWebDriver webDriver; - + bool mIsDeviceConnected = false; string mDefaultURL = null; @@ -328,9 +327,9 @@ public bool ConnectToAppium() isAppiumSession = true, BusinessFlow = this.BusinessFlow, PomCategory = this.PomCategory - }; + }; mSeleniumDriver.StopProcess = this.StopProcess; - + if (AppType == eAppType.Web && mDefaultURL != null) { try @@ -744,7 +743,7 @@ private void UIElementActionHandler(ActUIElement act) act.Error = ex.Message; } } - + /// /// Legacy Support /// @@ -992,6 +991,7 @@ private void MobileDeviceActionHandler(ActMobileDevice act) { switch (act.MobileDeviceAction) { + case ActMobileDevice.eMobileDeviceAction.TapXY: TapXY(Convert.ToInt32(act.X1.ValueForDriver), Convert.ToInt32(act.Y1.ValueForDriver)); break; @@ -1224,7 +1224,7 @@ private void MobileDeviceActionHandler(ActMobileDevice act) int i = 0; foreach (var c in Driver.Contexts) { - act.AddOrUpdateReturnParamActual("Context " + i+1, c.ToString()); + act.AddOrUpdateReturnParamActual("Context " + i + 1, c.ToString()); } break; @@ -1232,6 +1232,118 @@ private void MobileDeviceActionHandler(ActMobileDevice act) Driver.Context = act.ActionInput.ValueForDriver; break; + case ActMobileDevice.eMobileDeviceAction.OpenDeeplink: + OpenDeeplink(act.ActionInput.ValueForDriver, act.ActionAppPackage.ValueForDriver, GetAppPackageNameByOs()); + break; + + case ActMobileDevice.eMobileDeviceAction.IsKeyboardVisible: + act.AddOrUpdateReturnParamActual("Is Keyboard Visible", IsDeviceKeyboardVisible().ToString()); + break; + + case ActMobileDevice.eMobileDeviceAction.IsLocked: + act.AddOrUpdateReturnParamActual("Is Device Locked", IsDeviceLocked().ToString()); + break; + + case ActMobileDevice.eMobileDeviceAction.IsAppInstalled: + act.AddOrUpdateReturnParamActual("Is App Installed", IsDeviceAppInstalled(act.ActionAppPackage.ValueForDriver).ToString()); + break; + + case ActMobileDevice.eMobileDeviceAction.RemoveApp: + RemoveDeviceApp(act.ActionAppPackage.ValueForDriver); + break; + + case ActMobileDevice.eMobileDeviceAction.QueryAppState: + act.AddOrUpdateReturnParamActual("App State", QueryAppState(act.ActionAppPackage.ValueForDriver).ToString()); + break; + + case ActMobileDevice.eMobileDeviceAction.RotateSimulation: + switch (act.RotateDeviceState) + { + case ActMobileDevice.eRotateDeviceState.Landscape: + { + SwitchToLandscape(); + break; + } + case ActMobileDevice.eRotateDeviceState.Portrait: + { + SwitchToPortrait(); + break; + } + } + NotifyDeviceRotation(); + break; + + case ActMobileDevice.eMobileDeviceAction.RunScript: + RunScriptOnDevice(act.ActionInput.ValueForDriver); + break; + + case ActMobileDevice.eMobileDeviceAction.StartRecordingScreen: + StartDeviceScreenRecording(); + break; + + case ActMobileDevice.eMobileDeviceAction.StopRecordingScreen: + string pathRecording = StopRecordingScreen(act.FilePathInput.ValueForDriver).ToString(); + act.AddOrUpdateReturnParamActual("ScreenRecordingFilePath", pathRecording); + Act.AddArtifactToAction(Path.GetFileName(pathRecording), act, pathRecording); + break; + + case ActMobileDevice.eMobileDeviceAction.HideKeyboard: + HideKeyboard(); + break; + + case ActMobileDevice.eMobileDeviceAction.PushFileToDevice: + PushFileToDevice(act.FilePathInput.ValueForDriver, act.FolderPathInput.ValueForDriver); + break; + + case ActMobileDevice.eMobileDeviceAction.PullFileFromDevice: + PullFileFromDevice(act.FilePathInput.ValueForDriver, act.FolderPathInput.ValueForDriver); + break; + + case ActMobileDevice.eMobileDeviceAction.SetClipboardText: + SetClipboardText(act.ActionInput.ValueForDriver); + break; + + case ActMobileDevice.eMobileDeviceAction.GetClipboardText: + act.AddOrUpdateReturnParamActual("Get Clipboard Text", GetClipboardText()); + break; + + case ActMobileDevice.eMobileDeviceAction.GetDeviceLogs: + string deviceLogsPath = GetDeviceLogs(act.FolderPathInput.ValueForDriver); + act.AddOrUpdateReturnParamActual("DeviceLogFilePath", deviceLogsPath); + Act.AddArtifactToAction(Path.GetFileName(deviceLogsPath), act, deviceLogsPath); + break; + + case ActMobileDevice.eMobileDeviceAction.GetSpecificPerformanceData: + switch (act.PerformanceTypes) + { + case ActMobileDevice.ePerformanceTypes.Cpuinfo: + { + GetSpecificPerformanceData(act.ActionAppPackage.ValueForDriver, act.PerformanceTypes.ToString(), act); + break; + } + case ActMobileDevice.ePerformanceTypes.Memoryinfo: + { + GetSpecificPerformanceData(act.ActionAppPackage.ValueForDriver, act.PerformanceTypes.ToString(), act); + break; + } + case ActMobileDevice.ePerformanceTypes.Batteryinfo: + { + GetSpecificPerformanceData(act.ActionAppPackage.ValueForDriver, act.PerformanceTypes.ToString(), act); + break; + } + case ActMobileDevice.ePerformanceTypes.Networkinfo: + { + GetSpecificPerformanceData(act.ActionAppPackage.ValueForDriver, act.PerformanceTypes.ToString(), act); + break; + } + case ActMobileDevice.ePerformanceTypes.Diskinfo: + { + GetSpecificPerformanceData(act.ActionAppPackage.ValueForDriver, act.PerformanceTypes.ToString(), act); + break; + } + } + break; + default: throw new Exception("Action unknown/not implemented for the Driver: '" + this.GetType().ToString() + "'"); } @@ -1368,7 +1480,7 @@ private void ActScreenShotHandler(Act act) } } - private Tuple GetUserCustomeScreenshotSize() + private Tuple GetUserCustomeScreenshotSize() { int? customeWidth = null; int? customeHeight = null; @@ -2513,6 +2625,9 @@ ObservableList IWindowExplorer.GetElementProperties(ElementInfo return list; } + + + public event RecordingEventHandler RecordingEvent; void IRecord.ResetRecordingEventHandler() @@ -2601,7 +2716,10 @@ public void UnHighLightElements() OnDriverMessage(eDriverMessageType.UnHighlightElement); } - + public void NotifyDeviceRotation() + { + OnDriverMessage(eDriverMessageType.RotateEvent); + } public bool TestElementLocators(ElementInfo EI, bool GetOutAfterFoundElement = false, ApplicationPOMModel mPOM = null) { if (AppType == eAppType.Web) @@ -2880,7 +2998,7 @@ public Byte[] GetScreenshotImage() return null; } - private Byte[] GetScreenshotImageFromDriver(int? width = null, int ? height = null) + private Byte[] GetScreenshotImageFromDriver(int? width = null, int? height = null) { int screenshotWidth = 0; int screenshotHeight = 0; @@ -2904,7 +3022,7 @@ private Byte[] GetScreenshotImageFromDriver(int? width = null, int ? height = nu if (height != null) { screenshotHeight = height.Value; - } + } // Convert screenshot to Image for resizing using (var stream = new MemoryStream(screenshot.AsByteArray)) @@ -2997,9 +3115,9 @@ public void PerformDrag(Point start, Point end, TimeSpan pressDuration, TimeSpan RecordingOperations(mobDevAction); } } - + public void SwitchToLandscape() - { + { try { Driver.Orientation = ScreenOrientation.Landscape; @@ -3014,7 +3132,7 @@ public void SwitchToPortrait() { try { - Driver.Orientation = ScreenOrientation.Portrait; + Driver.Orientation = ScreenOrientation.Portrait; } finally { @@ -3287,7 +3405,7 @@ private void CalculateMobileDeviceScreenSizes() mWindowScaleFactor = 1; } mWindowWidth = (int)(windowSize.Width * mWindowScaleFactor); - mWindowHeight = (int)(windowSize.Height * mWindowScaleFactor); + mWindowHeight = (int)(windowSize.Height * mWindowScaleFactor); } catch (Exception ex) { @@ -3780,7 +3898,257 @@ public ObservableList GetElementFriendlyLocators(ElementInfo Ele { throw new NotImplementedException(); } - } -} + public string GetAppPackageNameByOs() + { + return Driver is AndroidDriver ? "package" : "bundleId"; + } + public string SetFilePath(string FileType, string FilePath, string FileName) + { + string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss"); + string fileName = Path.GetFileName(FilePath); + string targetFile = string.IsNullOrEmpty(fileName) ? Path.Combine(FilePath, $"{FileName}_{timestamp}.{FileType}") : $"{FilePath}.{FileType}"; + return targetFile; + } + + public object OpenDeeplink(string appLink, string appPackage, string osType) + { + var args = new Dictionary + { + { "url", appLink }, { osType, appPackage } + }; + return Driver is AndroidDriver ? ((AndroidDriver)Driver).ExecuteScript("mobile:deepLink", args) : ((IOSDriver)Driver).ExecuteScript("mobile:deepLink", args); + + } + + public bool IsDeviceKeyboardVisible() + { + return Driver.IsKeyboardShown(); + } + + public bool IsDeviceLocked() + { + return (bool)Driver.ExecuteScript("mobile:isLocked"); + } + + public bool IsDeviceAppInstalled(string appPackage) + { + return Driver.IsAppInstalled(appPackage); + } + + public void RemoveDeviceApp(string appPackage) + { + Driver.RemoveApp(appPackage); + } + + public AppState QueryAppState(string appId) + { + return Driver is AndroidDriver ? ((AndroidDriver)Driver).GetAppState(appId): ((IOSDriver)Driver).GetAppState(appId); + } + + public void RotateSimulation(string state) + { + if(state is "Landscape") + { + SwitchToLandscape(); + } + else + { + SwitchToPortrait(); + } + } + + public void RunScriptOnDevice(string script) + { + try + { + Driver.ExecuteScript(script); + } + catch (Exception ex) + { + throw new($"An error occurred while running script: {ex.Message}"); + } + } + + public void StartDeviceScreenRecording() + { + try + { + if (Driver is AndroidDriver) + { + var androidOptions = new AndroidStartScreenRecordingOptions().WithTimeLimit(TimeSpan.FromSeconds(1800)).WithBitRate(4000000).WithVideoSize("720x1280"); // max duration recording: 30 min + ((AndroidDriver)Driver).StartRecordingScreen(androidOptions); + } + else if (Driver is IOSDriver) + { + var iosOptions = new IOSStartScreenRecordingOptions() + .WithTimeLimit(TimeSpan.FromSeconds(1800)) // Set the same time limit + .WithVideoType("h264") // Use "h264" for efficient compression + .WithVideoQuality(IOSStartScreenRecordingOptions.VideoQuality.HIGH) // High quality for better resolution + .WithVideoScale("720:1280"); // Scale the video to match Android's resolution + ((IOSDriver)Driver).StartRecordingScreen(iosOptions); + } + } + catch (Exception ex) + { + throw new($"An error occurred while recording screen: {ex.Message}"); + } + } + + public string StopRecordingScreen(string path) + { + string targetFile = SetFilePath("mp4", path, "Mobile_Recording"); + string videoBase64 = string.Empty; + if (Driver is AndroidDriver) + { + videoBase64 = ((AndroidDriver)Driver).StopRecordingScreen(); + } + else + { + videoBase64 = ((IOSDriver)Driver).StopRecordingScreen(); + } + byte[] videoBytes = Convert.FromBase64String(videoBase64); + File.WriteAllBytes(targetFile, videoBytes); //"format mp4" + return targetFile; + } + + public void HideKeyboard() + { + try + { + if (Driver is AndroidDriver) + { + ((AndroidDriver)Driver).HideKeyboard("Done"); + } + else if (Driver is IOSDriver) + { + ((IOSDriver)Driver).HideKeyboard(); + } + } + catch (Exception ex) + { + throw new($"Failed to hide the keyboard: {ex.Message}"); + } + } + + public void PushFileToDevice(string LocalFilePath, string DeviceTargerFolder) + { + byte[] fileContent = System.IO.File.ReadAllBytes(DeviceTargerFolder); + string fileName = Path.GetFileName(DeviceTargerFolder); + if (Driver is IOSDriver) + { + ((IOSDriver)Driver).PushFile($"{LocalFilePath}/{fileName}", fileContent); + } + else + { + ((AndroidDriver)Driver).PushFile($"{LocalFilePath}/{fileName}", fileContent); + } + } + + public void PullFileFromDevice(string DeviceFilePath, string LocalFolderPath) + { + byte[] fileContent; + string fileName = Path.GetFileName(LocalFolderPath); + if (Driver is IOSDriver) + { + fileContent = ((IOSDriver)Driver).PullFile($"{LocalFolderPath}"); + } + else + { + fileContent = ((AndroidDriver)Driver).PullFile($"{LocalFolderPath}"); + } + // Save the file content to the local file path + System.IO.File.WriteAllBytes($"{DeviceFilePath}{fileName}", fileContent); + } + + public void SetClipboardText(string text) + { + if (Driver is IOSDriver) + { + ((IOSDriver)Driver).SetClipboardText(text, ""); + } + else + { + ((AndroidDriver)Driver).SetClipboardText(text, ""); + } + } + + public void GetSpecificPerformanceData(string appPackage, string specificData, ActMobileDevice act) + { + IList perfData = ((AndroidDriver)Driver).GetPerformanceData(appPackage, specificData, 5); + var dict = new Dictionary(); + var keys = (IList)perfData[0]; // keys data + var values = (IList)perfData[1]; // values data + for (int i = 0; i < keys.Count; i++) + { + string key = keys[i].ToString(); + object value = values[i]; + dict[key] = value; + } + foreach (var entry in dict) + { + if(entry.Key!=null) + { + string valueStr = entry.Value?.ToString() ?? string.Empty; // Convert null value to empty string + act.AddOrUpdateReturnParamActual(entry.Key.ToString(), valueStr); + } + } + } + + public string GetDeviceLogs(string path) + { + string targetFile = SetFilePath("txt", path, "DeviceLogs"); + // Get device logs + var logEntries = Driver.Manage().Logs.GetLog("logcat").ToList(); + // Create and write to the file + using (StreamWriter writer = new StreamWriter(targetFile, append: true)) + { + foreach (var logEntry in logEntries) + { + writer.WriteLine($"{logEntry.Timestamp}: {logEntry.Message}"); + } + } + return targetFile; + } + + //public void TypeUsingIOSkeyboard(string text) + //{ + // Driver.ExecuteScript("mobile: type", new Dictionary { { "text", text } }); + //} + + //public void ClearAppdata(string appId) + //{ + // ((AndroidDriver)Driver).ExecuteScript("mobile: clearApp", new Dictionary { { "appId", appId } }); + //} + + public string GetClipboardText() + { + if (Driver is IOSDriver) + { + return ((IOSDriver)Driver).GetClipboardText(); + } + else + { + return ((AndroidDriver)Driver).GetClipboardText(); + } + } + + public void InstallApp(string appPath) + { + if (Driver is AndroidDriver) + { + ((AndroidDriver)Driver).InstallApp(appPath); + } + else if (Driver is IOSDriver) + { + ((IOSDriver)Driver).InstallApp(appPath); + } + else + { + throw new InvalidOperationException("Unsupported driver type"); + } + + } + } +} \ No newline at end of file diff --git a/Ginger/GingerCoreNET/RunLib/DriverBase.cs b/Ginger/GingerCoreNET/RunLib/DriverBase.cs index f23103c2b4..b3558dc4a6 100644 --- a/Ginger/GingerCoreNET/RunLib/DriverBase.cs +++ b/Ginger/GingerCoreNET/RunLib/DriverBase.cs @@ -199,7 +199,8 @@ public enum eDriverMessageType ActionPerformed, RecordingEvent, HighlightElement, - UnHighlightElement + UnHighlightElement, + RotateEvent, } public void OnDriverMessage(eDriverMessageType DriverMessageType, object CustomSenderObj = null)