Repository navigation
PANA-8613: View traversal and decomposition - #3728
jonathanmos wants to merge 10 commits into
Conversation
|
✅ All CI checks and tests passed. Datadog automation helped this PR pass. 🎉 All green!🧪 All tests passed 🔄 Datadog retried 1 test - 1 passed on retry 🎯 Code Coverage (details) 🔗 Commit SHA: b4e4f19 | Docs | View more details | Give us feedback! |
1dd5cfc to
50400d0
Compare
92ae883 to
5ce8684
Compare
50400d0 to
35e15c5
Compare
6e5525f to
e67102f
Compare
06dc1f8 to
783469c
Compare
0168738 to
a4083d3
Compare
783469c to
902b1be
Compare
a4083d3 to
5287820
Compare
a21f246 to
357bf07
Compare
294da51 to
fd9fa08
Compare
5287820 to
5b481bc
Compare
bd69260 to
751e07a
Compare
883ec03 to
b94ea39
Compare
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
Security findingsAdvisory findings (1)
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b94ea39e26
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
🛡️ Codex Security Review · Automatically triggered
Here are some automated security review suggestions for this pull request.
Reviewed commit: b94ea39e26
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
Collect touch overrides in each capture and publish them only after all windows complete. Cancelled or aborted captures discard their partial overrides without contaminating a later generation. Cover queued cancellation, aborted traversal, and atomic publication. Validated composition and touch-privacy unit tests and ktlint.
Recheck the recording time bank before every resumed slice and start the slice clock when execution begins. Queue time continues to count toward the generation deadline without consuming a slice allowance. Cover denied resumes, budget recovery, and delayed continuations. Validated composition and touch-privacy unit tests and ktlint.
Use effective child drawing order for traversal and occlusion, including custom order and elevation. Respect child and padding clipping and exclude restrictively clipped siblings from full-occlusion culling. Carry accumulated clip intersections to avoid copying ancestor lists. Add drawing-order, clipping, occlusion, and deep-hierarchy regressions. Validated composition and touch-privacy unit tests and ktlint.
Mark WebView mapping results as terminal so traversal emits the WebView slot without separately capturing its implementation children. Cover native descendants, hidden WebViews, and ordinary containers. Validated composition and touch-privacy unit tests and ktlint.
Filter window interception and capture by the attached root handler. Defer detached roots and abort a partial capture if ownership is lost before visiting or resuming a window. Remove draw listeners through their original observer. Secondary-thread windows are explicitly outside composition capture. Cover ownership filtering, attachment changes, and observer cleanup. Validated full debug/release unit suites, ktlint, Detekt, release lint, and API surface checks.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e5db3ff2fc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| windowLayers += result.rootLayer | ||
| layers += result.layers | ||
| wireframes += result.wireframes | ||
| touchOverrideAreas += result.touchOverrideAreas |
There was a problem hiding this comment.
Scope touch overrides to the dispatching window
When windows overlap, merging every window's override map lets an obscured lower window control privacy for touches dispatched to the top window. For example, with global HIDE, an activity containing a SHOW region beneath an untagged modal dialog causes touches on the dialog to be recorded because every CompositionWindowTouchCallback consults this shared merged map. Keep overrides window-specific or exclude lower-window regions covered by higher windows.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Valid issue. will address per-window touch privacy isolation in a follow-up PR before release to keep this PR focused on view traversal and decomposition.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 51d12d5d5c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 623d5e7400
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| val viewArea = Rect( | ||
| x, | ||
| y, | ||
| x + view.width, | ||
| y + view.height |
There was a problem hiding this comment.
Clip touch overrides to the effective visible region
When a SHOW-tagged child extends outside a clipping parent, this raw view rectangle includes pixels where the child cannot be drawn or receive the touch. With global touch privacy set to HIDE, a touch handled by another view in that clipped-out area is therefore recorded because it still falls inside this override. Intersect the override with ancestor, padding, and explicit clip constraints before publishing it.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
will be addressed in a followup pr
623d5e7 to
85a072b
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 85a072bd65
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
85a072b to
561fb40
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 561fb40a1a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
561fb40 to
96247a0
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 96247a0233
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
96247a0 to
a27f444
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a27f444b06
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| val inheritedClip = if (item.clipToBounds) item.ancestorClip.intersectWith(bounds) else item.ancestorClip | ||
| val clip = view.clipBoundsOnScreen(state.screenDensity)?.let { inheritedClip.intersectWith(it) } | ||
| ?: inheritedClip |
There was a problem hiding this comment.
Apply clipToOutline to the captured subtree
When a view uses clipToOutline = true, such as a rounded card or an oval container, Android clips the view and its descendants to the outline, but this path only incorporates rectangular ancestor and clipBounds constraints. The replay therefore renders child content and backgrounds into corners or regions that are absent on screen. Resolve the view outline into a layer clip modifier, or otherwise fall back when the outline cannot be represented.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
will be addressed in a followup pr
| val orderedWindows = orderedDecorViews.mapNotNull { root -> | ||
| trackedByDecorView[root] ?: windowFromDecorView(root) | ||
| } |
There was a problem hiding this comment.
Intercept touches for unresolved untracked roots
When an untracked root cannot be converted to a Window—notably a PopupWindow root, or a dialog decor when private-field reflection is blocked—it remains in decorViews and is captured visually, but mapNotNull silently omits it from windows. No CompositionWindowTouchCallback is then installed for that root, so every interaction inside the displayed popup or dialog is absent from the replay. Provide a root-level touch fallback for unresolved roots rather than dropping them only from touch interception.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
will be addressed in a followup pr
a27f444 to
b4e4f19
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b4e4f19040
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| interceptor.intercept(resolved.decorViews) | ||
| touchInterceptor.intercept(resolved.windows) |
There was a problem hiding this comment.
Delay touch interception until privacy areas are ready
When recording starts or an attached window is newly discovered with global touch privacy set to SHOW, this installs its touch callback immediately after merely requesting a delayed capture. The override map is still empty until the 64 ms-delayed traversal finishes, so touches on views tagged HIDE during that interval are recorded using the global SHOW policy. Delay enabling the touch callback for a window until its first complete privacy map is published, or otherwise keep touch recording fail-closed during initialization.
Useful? React with 👍 / 👎.
|
|
||
| collectTouchOverrideArea(view, state) | ||
|
|
||
| val bounds = viewBoundsResolver.resolveViewGlobalBounds(view, state.screenDensity).toCaptured() |
There was a problem hiding this comment.
Preserve scale and rotation in captured layers
For any view with non-default scaleX, scaleY, or rotation—such as during a common property animation—the bounds resolver still returns the untransformed width and height, and the resulting layer records only an opacity modifier. Its text, background, and subtree are therefore replayed as an unscaled, unrotated rectangle even though Android renders a transformed view. Encode the spatial transform on the layer or capture the transformed output instead.
Useful? React with 👍 / 👎.
| return if (textView.text.isNullOrEmpty()) { | ||
| resolveHintTextColor(textView) | ||
| } else { | ||
| colorStringFormatter.formatColorAndAlphaAsHexString(textView.currentTextColor, OPAQUE_ALPHA_VALUE) |
There was a problem hiding this comment.
Preserve alpha from the current text color
When a nonempty TextView uses a translucent current color—commonly a disabled or secondary-text color from a state list—passing OPAQUE_ALPHA_VALUE replaces that color's alpha with 0xff. The layer opacity only represents View.alpha, so it cannot restore this per-color transparency and the replay renders the text fully opaque. Serialize the alpha already present in currentTextColor instead.
Useful? React with 👍 / 👎.
What does this PR do?
This is the third PR in the new composition-based Session Replay pipeline. It adds native View traversal and snapshot production to the new pipeline, covering text, WebView placeholders, hidden-view placeholders, and background shapes.
Capture can pause and resume within a window while respecting time budgets and cancellation. It preserves drawing order and clipping, avoids copying ancestor bounds at every level, and prevents cancelled captures from carrying partial touch-privacy overrides into later captures.
Motivation
Build on the capture orchestration introduced in the previous PR by producing real snapshots from the View hierarchy.
Additional Notes
Review checklist (to be filled by reviewers)