mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
fix(ioscompanion): retry describe past transient collapsed accessibility dumps
This commit is contained in:
1 parent
8b7a51c5b5
commit
a745ec7938
2 files changed
+44
-1
No files matched your search
@@ -660,8 +660,18 @@ func (d *Driver) ForegroundApp(ctx context.Context) (string, error) {
|
|||||||
return other, nil
|
return other, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// describeAll fetches the flat accessibility dump with one-restart recovery.
|
// collapsedDumpRetries and collapsedDumpDelay bound how long describeAll waits
|
||||||
|
// out a collapsed accessibility dump. The bridge briefly reports only the app
|
||||||
|
// shell (no UI content) during cold start and screen transitions; it recovers
|
||||||
|
// within a few hundred milliseconds. Re-fetching past the collapse keeps the
|
||||||
|
// runner from acting on, and snapshotting, an empty tree.
|
||||||
|
const collapsedDumpRetries = 6
|
||||||
|
const collapsedDumpDelay = 150 * time.Millisecond
|
||||||
|
|
||||||
|
// describeAll fetches the flat accessibility dump with one-restart recovery,
|
||||||
|
// retrying past a transient collapsed dump so callers see real UI content.
|
||||||
func (d *Driver) describeAll(ctx context.Context) ([]byte, error) {
|
func (d *Driver) describeAll(ctx context.Context) ([]byte, error) {
|
||||||
|
fetch := func() ([]byte, error) {
|
||||||
var dump []byte
|
var dump []byte
|
||||||
err := d.withRecovery(ctx, func() error {
|
err := d.withRecovery(ctx, func() error {
|
||||||
info, infoErr := d.companion.AccessibilityInfo(ctx)
|
info, infoErr := d.companion.AccessibilityInfo(ctx)
|
||||||
@@ -672,6 +682,25 @@ func (d *Driver) describeAll(ctx context.Context) ([]byte, error) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
return dump, err
|
return dump, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dump, err := fetch()
|
||||||
|
if err != nil {
|
||||||
|
return dump, err
|
||||||
|
}
|
||||||
|
for attempt := 0; attempt < collapsedDumpRetries && dumpIsCollapsed(dump); attempt++ {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return dump, nil
|
||||||
|
case <-time.After(collapsedDumpDelay):
|
||||||
|
}
|
||||||
|
next, nextErr := fetch()
|
||||||
|
if nextErr != nil {
|
||||||
|
return dump, nil
|
||||||
|
}
|
||||||
|
dump = next
|
||||||
|
}
|
||||||
|
return dump, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeRunner builds the input runner backed by the current transport. The text
|
// makeRunner builds the input runner backed by the current transport. The text
|
||||||
|
|||||||
@@ -19,6 +19,20 @@ type rawFrame struct {
|
|||||||
// it maps to an empty value rather than surfacing as literal field text.
|
// it maps to an empty value rather than surfacing as literal field text.
|
||||||
const emptyFieldValueSentinel = "Invalid"
|
const emptyFieldValueSentinel = "Invalid"
|
||||||
|
|
||||||
|
// dumpIsCollapsed reports whether a flat describe-all dump carries no real UI
|
||||||
|
// content: it is empty or holds only the application shell. The accessibility
|
||||||
|
// bridge briefly returns this state during cold start and screen transitions
|
||||||
|
// before the real tree reappears.
|
||||||
|
func dumpIsCollapsed(dump []byte) bool {
|
||||||
|
elements := decodeDump(dump)
|
||||||
|
for _, element := range elements {
|
||||||
|
if element.Type != "" && element.Type != "Application" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// rawElement is one entry in the flat describe-all dump returned by the
|
// rawElement is one entry in the flat describe-all dump returned by the
|
||||||
// simulator companion. Only the fields the mapper consumes are declared;
|
// simulator companion. Only the fields the mapper consumes are declared;
|
||||||
// unknown fields are ignored.
|
// unknown fields are ignored.
|
||||||
|
|||||||
Reference in new issue
Block a user