-
Notifications
You must be signed in to change notification settings - Fork 62
Improve mobile element highlighting and rectangle accuracy #4480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ limitations under the License. | |
| using Amdocs.Ginger.Common.Repository.ApplicationModelLib.POMModelLib; | ||
| using Amdocs.Ginger.Common.UIElement; | ||
| using Amdocs.Ginger.CoreNET; | ||
| using Amdocs.Ginger.CoreNET.Drivers.CoreDrivers.Mobile; | ||
| using Ginger.Actions.Locators.ASCF; | ||
| using Ginger.Actions.UserControls; | ||
| using Ginger.BusinessFlowsLibNew.AddActionMenu; | ||
|
|
@@ -1441,7 +1442,7 @@ private async Task HighlightSelectedElement(System.Drawing.Point ClickedPoint) | |
| } | ||
|
|
||
| // Draw rectangle in screenshot view using the element's (now fresh) bounds | ||
| DrawElementRectangleAsync(inspectElementInfo); | ||
| DrawElementRectangleAsync(inspectElementInfo, highlightInApp: false); | ||
|
|
||
| // Keep persistent highlighted element reference for UI flows | ||
| currentHighlightedElement = inspectElementInfo; | ||
|
|
@@ -1482,13 +1483,33 @@ private async Task HighlightSelectedElement(System.Drawing.Point ClickedPoint) | |
| } | ||
| } | ||
|
|
||
| private void DrawElementRectangleAsync(ElementInfo clickedElementInfo) | ||
| private void DrawElementRectangleAsync(ElementInfo clickedElementInfo, bool highlightInApp = true) | ||
| { | ||
| try | ||
| { | ||
| // remove previous rectangle | ||
| RemoveElemntRectangle(); | ||
|
|
||
| // For some Android paths the element is identified but bounds are not populated yet. | ||
| // Refresh once before rectangle math; if still invalid, skip drawing a misleading rectangle. | ||
| if (clickedElementInfo.Width <= 0 || clickedElementInfo.Height <= 0) | ||
| { | ||
| try | ||
| { | ||
| mWindowExplorerDriver?.UpdateElementInfoFields(clickedElementInfo); | ||
| } | ||
| catch (Exception exUpd) | ||
| { | ||
| Reporter.ToLog(eLogLevel.DEBUG, "DrawElementRectangleAsync: UpdateElementInfoFields failed before rectangle draw: " + exUpd.Message, exUpd); | ||
| } | ||
|
Comment on lines
+1501
to
+1504
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use Line 1503, Line 1637, and Line 1644 log caught failures with Suggested change- Reporter.ToLog(eLogLevel.DEBUG, "DrawElementRectangleAsync: UpdateElementInfoFields failed before rectangle draw: " + exUpd.Message, exUpd);
+ Reporter.ToLog(eLogLevel.ERROR, "DrawElementRectangleAsync: UpdateElementInfoFields failed before rectangle draw: " + exUpd.Message, exUpd);
- Reporter.ToLog(eLogLevel.DEBUG, "Driver HighLightElement failed", ex);
+ Reporter.ToLog(eLogLevel.ERROR, "Driver HighLightElement failed", ex);
- Reporter.ToLog(eLogLevel.DEBUG, "Request to driver highlight element failed", ex);
+ Reporter.ToLog(eLogLevel.ERROR, "Request to driver highlight element failed", ex);As per coding guidelines: Also applies to: 1635-1644 🤖 Prompt for AI Agents |
||
|
|
||
| if (clickedElementInfo.Width <= 0 || clickedElementInfo.Height <= 0) | ||
| { | ||
| Reporter.ToLog(eLogLevel.DEBUG, "DrawElementRectangleAsync: skipping rectangle draw due to invalid element bounds."); | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| // element bounds in source image/device coordinates | ||
| System.Drawing.Point ElementStartPoint = new System.Drawing.Point(clickedElementInfo.X, clickedElementInfo.Y); | ||
| System.Drawing.Point ElementMaxPoint = new System.Drawing.Point(clickedElementInfo.X + clickedElementInfo.Width, clickedElementInfo.Y + clickedElementInfo.Height); | ||
|
|
@@ -1597,28 +1618,31 @@ private void DrawElementRectangleAsync(ElementInfo clickedElementInfo) | |
| mScreenShotViewPage.xHighlighterBorder.Visibility = Visibility.Visible; | ||
| }), System.Windows.Threading.DispatcherPriority.Render); | ||
|
|
||
| // ask driver to highlight in the actual app as well (non-blocking) | ||
| try | ||
| if (highlightInApp) | ||
| { | ||
| var drv = mWindowExplorerDriver; | ||
| if (drv != null) | ||
| // ask driver to highlight in the actual app as well (non-blocking) | ||
| try | ||
| { | ||
| System.Threading.Tasks.Task.Run(() => | ||
| var drv = mWindowExplorerDriver; | ||
| if (drv != null) | ||
| { | ||
| try | ||
| { | ||
| drv.HighLightElement(clickedElementInfo, locateElementByItLocators: true); | ||
| } | ||
| catch (Exception ex) | ||
| System.Threading.Tasks.Task.Run(() => | ||
| { | ||
| Reporter.ToLog(eLogLevel.DEBUG, "Driver HighLightElement failed", ex); | ||
| } | ||
| }); | ||
| try | ||
| { | ||
| drv.HighLightElement(clickedElementInfo, locateElementByItLocators: true); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Reporter.ToLog(eLogLevel.DEBUG, "Driver HighLightElement failed", ex); | ||
| } | ||
| }); | ||
| } | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Reporter.ToLog(eLogLevel.DEBUG, "Request to driver highlight element failed", ex); | ||
| } | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Reporter.ToLog(eLogLevel.DEBUG, "Request to driver highlight element failed", ex); | ||
| } | ||
| } | ||
| catch (Exception ex) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1794,20 +1794,24 @@ private void EnsureDeviceBounds(ElementInfo ei) | |
| { | ||
| if (ei == null) return; | ||
|
|
||
| // If already have bounds property or width/height set - assume ok | ||
| if ((ei.Properties != null && ei.Properties.Any(p => string.Equals(p.Name, "bounds", StringComparison.InvariantCultureIgnoreCase))) | ||
| || (ei.Width > 0 && ei.Height > 0)) | ||
| // If we already have concrete size, nothing to do. | ||
| if (ei.Width > 0 && ei.Height > 0) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| // Try attribute "bounds" (common for Android UiAutomator) | ||
| string boundsAttr = null; | ||
| string boundsAttr = ei.Properties? | ||
| .FirstOrDefault(p => string.Equals(p.Name, "bounds", StringComparison.InvariantCultureIgnoreCase)) | ||
| ?.Value; | ||
| if (ei.ElementObject is IWebElement we) | ||
| { | ||
| try | ||
| { | ||
| boundsAttr = we.GetAttribute("bounds"); | ||
| if (string.IsNullOrEmpty(boundsAttr)) | ||
| { | ||
| boundsAttr = we.GetAttribute("bounds"); | ||
| } | ||
|
Comment on lines
+1804
to
+1814
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Refresh This now prefers 💡 Suggested fix- string boundsAttr = ei.Properties?
- .FirstOrDefault(p => string.Equals(p.Name, "bounds", StringComparison.InvariantCultureIgnoreCase))
- ?.Value;
+ string boundsAttr = null;
if (ei.ElementObject is IWebElement we)
{
try
{
- if (string.IsNullOrEmpty(boundsAttr))
- {
- boundsAttr = we.GetAttribute("bounds");
- }
+ boundsAttr = we.GetAttribute("bounds");
}
catch { boundsAttr = null; }
}
+
+ if (string.IsNullOrEmpty(boundsAttr))
+ {
+ boundsAttr = ei.Properties?
+ .LastOrDefault(p => string.Equals(p.Name, "bounds", StringComparison.InvariantCultureIgnoreCase))
+ ?.Value;
+ }- if (ei.Properties == null) ei.Properties = new ObservableList<ControlProperty>();
- ei.Properties.Add(new ControlProperty() { Name = "bounds", Value = $"[{l},{t}][{r},{b}]" });
+ if (ei.Properties == null) ei.Properties = new ObservableList<ControlProperty>();
+ var existingBounds = ei.Properties
+ .FirstOrDefault(p => string.Equals(p.Name, "bounds", StringComparison.InvariantCultureIgnoreCase));
+ if (existingBounds != null)
+ {
+ existingBounds.Value = $"[{l},{t}][{r},{b}]";
+ }
+ else
+ {
+ ei.Properties.Add(new ControlProperty() { Name = "bounds", Value = $"[{l},{t}][{r},{b}]" });
+ }Also applies to: 1835-1837 🤖 Prompt for AI Agents |
||
| } | ||
| catch { boundsAttr = null; } | ||
| } | ||
|
|
@@ -2932,6 +2936,16 @@ async void IWindowExplorer.HighLightElement( | |
| ElementInfo filteredElementInfo = | ||
| POMExecutionUtils.FilterElementDetailsByCategory(ElementInfo, PomCategory); | ||
|
|
||
| // Keep exact spied element identity when caller did not request locator-based re-resolution. | ||
| // FilterElementDetailsByCategory may strip ElementObject in some flows, which can cause | ||
| // fallback XY lookup to highlight a nearby element (seen on iOS). | ||
| if (!locateElementByItLocators && | ||
| filteredElementInfo.ElementObject == null && | ||
| ElementInfo.ElementObject != null) | ||
| { | ||
| filteredElementInfo.ElementObject = ElementInfo.ElementObject; | ||
| } | ||
|
|
||
| ((IWindowExplorer)mSeleniumDriver) | ||
| .HighLightElement(filteredElementInfo, locateElementByItLocators); | ||
|
|
||
|
|
@@ -3088,7 +3102,6 @@ private ElementInfo GetElementAtMousePosition() | |
| // ANDROID (mobile) + iOS → KEEP EXISTING LOGIC | ||
| // ================================================ | ||
| foundNode = FindElementXmlNodeByXY(mousePosCurrent.X, mousePosCurrent.Y, false).Result; | ||
|
|
||
| if (foundNode != null) | ||
| { | ||
| foundElement = GetElementInfoforXmlNode(foundNode).Result; | ||
|
|
@@ -3398,6 +3411,8 @@ private async Task<ElementInfo> GetElementInfoforXmlNode(XmlNode xmlNode) | |
| { | ||
| EI.X = Convert.ToInt32(boundsXY[0]); | ||
| EI.Y = Convert.ToInt32(boundsXY[1]); | ||
| EI.Width = Math.Max(0, Convert.ToInt32(boundsXY[2]) - EI.X); | ||
| EI.Height = Math.Max(0, Convert.ToInt32(boundsXY[3]) - EI.Y); | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Use the active driver field for element learning to avoid reference drift.
Line 269 calls
LearnElementInfoDetailsviaxWindowSelectionUC.mWindowExplorerDriverwhile this flow is guarded bymWindowExplorerDriver. Prefer a single source of truth here to avoid null/out-of-sync edge failures.Suggested change
📝 Committable suggestion
🤖 Prompt for AI Agents