Repository navigation
fix(ios): book every surface on the lit panel, not the first window #4122
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
Merged
Merged
Changes from all commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
9cfcc64
fix(ios): book every surface on the lit panel, not the first window
thymikee d4f80da
refactor(ios): resolve one lit-panel window per request
thymikee d7bbb85
docs: correct the lit-panel comments a review flagged
thymikee 3b0d2c4
fix(ios): fail closed when the lit panel cannot be booked
thymikee 3104c1a
fix(ios): order the panel-table back-off behind newer resolved reads
thymikee 0f8e83d
docs(adr): count the off-lit-panel capture refusal
thymikee 153a101
fix(ios): keep every lit-panel read on proven lit windows
thymikee 1156514
fix(ios): keep raw, unreadable-list and pin refusals on the lit panel
thymikee bc78936
fix(ios): let element search own the lit-panel refusal
thymikee 8bf2540
test(ios): share the lit-panel and penalized-clear test setups
thymikee f2452c3
docs(adr): qualify when customActions implies the private AX pin
thymikee 5b72da7
fix(ios): refuse an unread lit-panel window list instead of falling back
thymikee 45a4ad4
fix(ios): contain the lit-panel window walk and keep its refusals closed
thymikee 7e79b03
refactor(ios): drop the single-caller textInputAt and trim lit-panel …
thymikee 3e09282
fix(ios): route every lit-panel text-entry read through the element s…
thymikee f80aeef
fix(ios): book the lit panel's whole box for a window that leaves a s…
thymikee 160cd75
docs(ios): tighten the lit-panel booking comment
thymikee 319c2dc
test(ios): share the bound-input fixture target
thymikee a739321
fix(ios): propagate lit-panel refusals from the commit poll and clear…
thymikee bd46ee9
fix(ios): book the lit panel's screen box at the screen origin
thymikee c01b4c9
fix(ios): turn lit-panel taps about the screen, keep the window's tra…
thymikee 8ee8d47
test(ios): drive the lit-panel booking for a partial window; scope th…
thymikee 24be5ee
docs(adr): map each capture refusal to its cases and scope the window…
thymikee eaf6310
fix(ios): preserve screen points across lit-panel coordinate fallbacks
thymikee 7b7e0df
fix(ios): key lit-panel bookings by app and request identity
thymikee c1ad139
docs(adr): scope the panel-probe budget refusal to a named lit panel
thymikee 294c7c6
fix(ios): refuse unbooked lit-panel reference frames
thymikee 4d6f523
fix(ios): scope collapsed-tab candidates to the captured lit display
thymikee ec80eec
fix(ios): refuse unread lit-panel window frames
thymikee File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
131 changes: 131 additions & 0 deletions
131
apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerRequestPanel.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| import XCTest | ||
|
|
||
| // The lit panel of the command in flight (ADR 0025), main-owned and written behind main work a | ||
| // previous command left queued, so that work still reads its own command's panel. | ||
| struct LitPanelBookingKey: Equatable { | ||
| let bundleID: String | ||
| let requestID: UUID | ||
| } | ||
|
|
||
| struct LitPanelSurface { | ||
| let key: LitPanelBookingKey | ||
| let displayID: UInt | ||
| let window: XCUIElement | ||
| let frame: CGRect | ||
| } | ||
|
|
||
| /// The command's lit panel and what it booked on it. Read and written only on the main thread. | ||
| final class RunnerLitPanelState { | ||
| var requestID: UUID? | ||
| var panel: RunnerLitPanel? | ||
| var surface: LitPanelSurface? | ||
| } | ||
|
thymikee marked this conversation as resolved.
Resolved
|
||
|
|
||
| extension RunnerTests { | ||
| @discardableResult | ||
| func setRequestLitPanel(from command: Command) -> UUID { | ||
| let requestID = UUID() | ||
| var panel: RunnerLitPanel? | ||
|
thymikee marked this conversation as resolved.
Resolved
|
||
| if let fact = command.litPanel, fact.displayId != 0, fact.widthPt.isFinite, fact.heightPt.isFinite, | ||
| fact.widthPt > 0, fact.heightPt > 0 | ||
| { | ||
| panel = RunnerLitPanel(displayID: fact.displayId, widthPt: fact.widthPt, heightPt: fact.heightPt) | ||
| } | ||
| let state = litPanelState | ||
| let write = { | ||
| state.requestID = requestID | ||
| state.panel = panel | ||
| state.surface = nil | ||
| } | ||
| if Thread.isMainThread { | ||
| write() | ||
| } else { | ||
| DispatchQueue.main.async(execute: write) | ||
| } | ||
| return requestID | ||
| } | ||
|
|
||
| func endRequestLitPanel(_ requestID: UUID) { | ||
| let state = litPanelState | ||
| let clear = { | ||
| guard state.requestID == requestID else { return } | ||
| state.requestID = nil | ||
| state.panel = nil | ||
| state.surface = nil | ||
| } | ||
| if Thread.isMainThread { | ||
| clear() | ||
| } else { | ||
| DispatchQueue.main.async(execute: clear) | ||
| } | ||
| } | ||
|
|
||
| /// The lit panel the current request named, or nil for a single-panel request. Main only. | ||
| var requestLitPanel: RunnerLitPanel? { litPanelState.panel } | ||
|
|
||
| /// Books `app`'s lit-panel window for the request, or returns why it cannot. | ||
| func bookRequestLitPanelSurface(app: XCUIApplication) -> RunnerAppScreenCaptureFailure? { | ||
|
thymikee marked this conversation as resolved.
Resolved
|
||
| guard let litPanel = requestLitPanel else { return nil } | ||
|
thymikee marked this conversation as resolved.
Resolved
|
||
| guard let requestID = litPanelState.requestID, | ||
| let bundleID = safely("LIT_PANEL_APP_IDENTITY", { app.value(forKey: "bundleID") as? String })?.trimmedNonEmpty | ||
| else { return .unresolvedScreen } | ||
| let key = LitPanelBookingKey(bundleID: bundleID, requestID: requestID) | ||
| if litPanelState.surface?.key == key { return nil } | ||
| litPanelState.surface = nil | ||
|
thymikee marked this conversation as resolved.
Resolved
|
||
| var window: AnyObject? | ||
| var frame = CGRect.null | ||
| var screen: AnyObject? | ||
| let failure = RunnerResolveLitPanelWindow(app, litPanel, &window, &frame, &screen) | ||
| guard failure == .none, let element = window as? XCUIElement else { | ||
| return RunnerAppScreenCaptureFailure(failure == .none ? .unresolvedWindow : failure) | ||
| } | ||
| litPanelState.surface = LitPanelSurface(key: key, displayID: litPanel.displayID, window: element, frame: frame) | ||
| return nil | ||
| } | ||
|
|
||
|
thymikee marked this conversation as resolved.
Resolved
thymikee marked this conversation as resolved.
Resolved
|
||
| func requireRequestLitPanelSurface(app: XCUIApplication) throws -> LitPanelSurface { | ||
| if let refusal = bookRequestLitPanelSurface(app: app) { throw refusal } | ||
| guard let surface = litPanelState.surface else { | ||
| throw RunnerAppScreenCaptureFailure.unresolvedScreen | ||
| } | ||
| return surface | ||
| } | ||
|
|
||
| /// The roots of every element read: the app, or the windows proven on the lit display. A walk that | ||
|
thymikee marked this conversation as resolved.
Resolved
thymikee marked this conversation as resolved.
Resolved
|
||
| /// cannot read the list, or that records an issue (#2995), throws `APP_SCREEN_UNRESOLVED`. | ||
| func elementSearchRoots(root: XCUIElement, litDisplayID: UInt?) throws -> [XCUIElement] { | ||
| guard let litDisplayID else { return [root] } | ||
| var windows: [XCUIElement]? | ||
| let walk = holdingRecordedIssues { | ||
| windows = RunnerCopyLitPanelWindows(root, litDisplayID)?.compactMap { $0 as? XCUIElement } | ||
| #if AGENT_DEVICE_RUNNER_UNIT_TESTS | ||
| if litPanelWindowWalkIssueForTesting { | ||
| record(XCTIssue(type: .assertionFailure, compactDescription: "Window vanished during the lit-panel walk")) | ||
| } | ||
| #endif | ||
| } | ||
| guard walk.issues.isEmpty, walk.exceptionMessage == nil, let windows, !windows.isEmpty else { | ||
| for issue in walk.issues { | ||
| NSLog("AGENT_DEVICE_RUNNER_LIT_PANEL_WALK_ISSUE=%@", issue.compactDescription) | ||
| } | ||
| NSLog( | ||
| "AGENT_DEVICE_RUNNER_LIT_PANEL_WALK_REFUSED issues=%ld exception=%@ windows=%ld", | ||
| walk.issues.count, walk.exceptionMessage ?? "none", windows?.count ?? -1 | ||
| ) | ||
| throw RunnerAppScreenCaptureFailure.unresolvedScreen | ||
| } | ||
| return windows | ||
| } | ||
|
thymikee marked this conversation as resolved.
Resolved
|
||
|
|
||
| func elementQueries(app: XCUIApplication, matching type: XCUIElement.ElementType) throws -> [XCUIElementQuery] { | ||
| try elementQueries(root: app, matching: type, litDisplayID: requestLitPanel?.displayID) | ||
| } | ||
|
|
||
| func elementQueries( | ||
| root: XCUIElement, | ||
| matching type: XCUIElement.ElementType, | ||
| litDisplayID: UInt? | ||
| ) throws -> [XCUIElementQuery] { | ||
| try elementSearchRoots(root: root, litDisplayID: litDisplayID).map { $0.descendants(matching: type) } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.