Skip to content

[Android] Fix stale bottom safe area after Shell tab navigation with TabBarIsVisible=False - #36474

Merged
kubaflo merged 21 commits into
dotnet:inflight/currentfrom
praveenkumarkarunanithi:fix-36269
Oct 9, 2026
Merged

kubaflo merged 21 commits into
dotnet:inflight/currentfrom
praveenkumarkarunanithi:fix-36269

Conversation

@praveenkumarkarunanithi

@praveenkumarkarunanithi praveenkumarkarunanithi commented Jul 9, 2026 •

Copy link
Copy Markdown
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue.
Thank you!

Root Cause

On Android, a page's bottom safe area padding is derived from its current height—how far it extends into the navigation bar area. During Shell tab navigation with Shell.TabBarIsVisible="false", the page (which shares the Shell pager) is briefly re-measured at a reduced height as the TabBar animates back in on the other tab, and while it is shorter, its bottom padding is recalculated to zero.

This zeroing is triggered by PR #34324, which added a RequestApplyInsets dispatch when the TabBar transitions from hidden to visible (to fix the related empty-space issue, #33703). That dispatch runs while the returning page is still measured at the reduced height, so its bottom padding is recomputed to zero.

When the page grows back to full height, Android does not recompute safe area padding on a plain resize—only on an inset dispatch, a SafeAreaEdges change, or a configuration change. As a result, the stale zero padding persists and the content slides under the navigation bar.

Description of Change

When a safe area view is re-laid out at a new size, the fix requests Android to re-apply window insets during the layout pass so the bottom padding is recalculated against the updated height.

The fix is scoped to run only for views that explicitly opt into SafeAreaEdges or already have safe-area padding applied, so ordinary pages and normal size changes are unaffected. SoftInput-only edges are excluded while the keyboard is closed, since they need no padding then.

It reuses the existing layout and window inset handling, adding a small internal helper to decide eligibility and no new public API.

Because SafeAreaEdges can be applied either to a page or to a layout, the same change is applied to both ContentViewGroup and LayoutViewGroup.

Issues Fixed

Fixes #36269

Tested the behaviour in the following platforms

  • Android
  • Windows
  • iOS
  • Mac

Note

The test could not be added for Catalyst and Windows because SafeAreaEdges is not supported on these platforms.

Regression Details:

Regressed by PR #34324

Output Video

Before Issue Fix After Issue Fix
BeforeFix.42.mov
AfterFix.49.mov

@dotnet-policy-service dotnet-policy-service Bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Jul 9, 2026
@praveenkumarkarunanithi praveenkumarkarunanithi added platform/android area-safearea Issues/PRs that have to do with the SafeArea functionality partner/syncfusion Issues / PR's with Syncfusion collaboration and removed partner/syncfusion Issues / PR's with Syncfusion collaboration labels Jul 9, 2026
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 36474

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 36474"

@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jul 9, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expert Review — 1 findings

See inline comments for details.

Comment thread src/Core/src/Platform/Android/ContentViewGroup.cs Outdated
@MauiBot MauiBot added s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Jul 9, 2026
MauiBot

This comment was marked as outdated.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jul 9, 2026
@kubaflo

kubaflo commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

@kubaflo

This comment has been minimized.

@github-actions

This comment has been minimized.

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this ready for review?

@kubaflo

kubaflo commented Jul 12, 2026 •

Copy link
Copy Markdown
Contributor

Tests Failure Analysis

🔍 AI-generated preview — improved Tests Failure Analysis based on commit 1089273.
Manual preview of the multi-build base-branch regression diff (#36533) — not an automated workflow run.

Overall Needs human investigation Failures 14 Regressed vs base 0 Baseline 2 on base

Test Failure Review: Needs human investigation - click to expand

Overall verdict: Needs human investigation — but no PR-caused regressions. Against several recent main base builds, 0 of 14 distinct failures are regressions; 6 are dismissed as pre-existing flakiness. The verdict only stops short of green because of unexplained build legs with no extractable test name — nothing is provably caused by this change (expected for a WIP draft).

  • ● Unrelated — Shell navigation tests (~6 tests): NavEvents_ShellItemChanged_NavigatingEvent_*, NavEvents_GoToAsyncAbsoluteRoute_* flake intermittently on main itself (green on most base builds), so not this PR.
  • ℹ Uncertain — unexplained legs + 1 aborted check (~10 legs): Controls CarouselView/CollectionView legs and Publish … test results - build error steps carry no extractable test name — can't be attributed either way.

Coverage: 169 checks · 162 passing · 7 failing · 0 pending · 2 unmapped · 10 unexplained build legs · 1 aborted · 0 device-test unverified · 14 unattributed · 0 regressed-vs-base. Deterministic ceiling: Needs human investigation — 10 unexplained legs, 14 unattributed, 1 aborted; 0 regressed-vs-base.

Builds (this PR): maui-pr-uitests 1502162 (failed) · maui-pr-devicetests 1502163 (succeeded). Base sampling (main, ~5 recent builds per definition): maui-pr-uitests 1503618 · maui-pr-devicetests 1503431 (succeeded).

Scope: platform/android · area-safearea · partner/syncfusion. WIP draft. Base branch: main.

Recommended action

No genuine base-branch regression was isolated, but some legs could not be attributed — a human should glance at the Uncertain items above before merging.

@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jul 20, 2026
@MauiBot MauiBot added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-win AI found a better alternative fix than the PR and removed s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates labels Jul 20, 2026
MauiBot

This comment was marked as outdated.

PureWeen and others added 2 commits October 7, 2026 00:36
…dotnet#39188)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

<!-- Enter description of the fix in this section -->

Fix a confirmed startup-deadline regression in the CI-fix Azure DevOps
dispatcher introduced by dotnet#39147, and correct a separate, pre-existing
producer prompt contradiction that blocks mandatory safe-output
registration.

**Production evidence:** [run
37477952193](https://github.com/dotnet/maui/actions/runs/37477952193)
spent approximately 533 seconds between starting the 420-second deadline
and completing trusted checkout; [run
37485076087](https://github.com/dotnet/maui/actions/runs/37485076087)
spent approximately 494 seconds. Both then failed with `The variable
cannot be validated because the value 0 is not a valid value for the
DispatcherBudgetSeconds variable.`

**Root cause:** The script parameter `[ValidateRange(1,
540)][int]$DispatcherBudgetSeconds` and top-level
`$script:DispatcherBudgetSeconds` are the same validated PowerShell
variable. Clamping valid caller input `420` against an already-expired
absolute deadline assigns `0` to that variable, triggering validation
before explicit budget-exhaustion reporting can run. Extracted helper
tests did not exercise this entrypoint initialization.

**Correction:**
- Store the clamped runtime allowance in the distinct
`EffectiveDispatcherBudgetSeconds` variable and update remaining-budget
helpers and their extracted-test state consistently. Caller budget `0`
remains invalid.
- Fail startup explicitly with `[dispatcher-budget-exhausted]` when
preparation has consumed the deadline, before PR discovery,
authentication, HTTP, or sleep. Write a failed preparation/deadline job
summary and state `No queue POST was attempted.` This also fails rather
than claiming successful no-work reconciliation when the deadline is
expired.
- Limit trusted checkout to the standalone
`/.github/scripts/Queue-CiFixAzdoValidation.ps1` using non-cone sparse
checkout. The existing SHA-pinned checkout v7.0.1 supports exact
patterns and automatically uses `blob:none` for sparse fetches. Preserve
`github.sha`, `fetch-depth: 1`, and `persist-credentials: false`; never
fetch or execute PR code.
- Document preparation behavior and limitations. Keep the absolute
pre-checkout 420-second deadline and ten-minute hard job timeout
unchanged; do not restart or extend either allowance.

**Validation:** Baseline dispatcher suite: 73 passed. Before the script
correction, the six new actual-entrypoint cases produced four expected
expired-deadline failures with the original validation exception and two
passing caller-validation/future-deadline cases. After correction, all
**79 tests passed**, including existing helper/queue regressions.
Expired cases assert the preparation summary, explicit prefix, no-POST
message, and zero HTTP/sleep calls; a native PowerShell process asserts
nonzero exit. The valid future deadline still produces the three
verified offline pipeline payloads.

Exact final commands and results:

```powershell
pwsh -NoProfile -Command '$env:PSModulePath = "/Users/shneuvil/.copilot/session-state/237fbb01-6532-4170-9f5e-6af14fa3a5e0/files/powershell-modules" + [IO.Path]::PathSeparator + $env:PSModulePath; Import-Module Pester -ErrorAction Stop; Invoke-Pester -Path .github/scripts/Queue-CiFixAzdoValidation.Tests.ps1 -Output Normal -CI'
# Passed: 79; failed/skipped: 0. Reused existing Pester; no dependency installation.

pwsh -NoProfile -Command '$files = @(".github/scripts/Queue-CiFixAzdoValidation.ps1", ".github/scripts/Queue-CiFixAzdoValidation.Tests.ps1"); foreach ($file in $files) { $tokens = $null; $errors = $null; [void][System.Management.Automation.Language.Parser]::ParseFile((Join-Path $PWD $file), [ref]$tokens, [ref]$errors); if ($errors.Count) { $errors | ForEach-Object { Write-Error $_ }; exit 1 }; Write-Output "Parse passed: $file" }'
# Passed: both PowerShell files parsed without errors.
```

```bash
actionlint .github/workflows/ci-fix-azdo-validation.yml
# Passed.
git diff --check
# Passed.
```

**Limits:** The sparse-checkout assertion is a static
configuration/trust regression, not a hosted checkout timing
measurement. Production checkout performance remains unproven; checkout
or PowerShell startup exceeding the ten-minute hard guard can still
cancel the job before a summary is written. No live Azure queue
requests, manual workflow dispatches/reruns, `/azp` requests, or
credential/permission/model-policy changes were performed. There is
still no successful eligible-PR Azure canary evidence here; this PR does
not establish Azure permissions or exact-head check linkage for any of
the three pipelines.

**Related producer blocker (pre-existing, not introduced by dotnet#39147):**
[main producer run
37464881821](https://github.com/dotnet/maui/actions/runs/37464881821)
and [net11 producer run
37465231994](https://github.com/dotnet/maui/actions/runs/37465231994)
concluded success but emitted `missing_tool` / `report_incomplete`. The
net11 diagnostic explicitly says mandatory expectation registration
requires PowerShell but the run instructions exclude it. The main
diagnostic likewise reports the prompt-specific `no-pwsh` restriction,
alongside separate unavailable cited Azure timeline evidence. This is an
upstream producer blocker: a compliant PR cannot reach dispatcher
validation if required registration is prohibited by its own prompt.

Both producers already allow `pwsh` in `tools.bash`, and Hard Rule 11
requires `Register-CiFixSafeOutputExpectation.ps1` or atomic
validation/registration via `Test-CiFixTransport.ps1`. Their bottom
Environment constraints sections nevertheless said `no pwsh`. The
mirrored correction changes only that prose: explicitly identify `pwsh`
availability for those deterministic helpers, retain `no gh` / `no
python` and `curl` + `jq` API guidance, and reiterate existing
fail-closed registration/transport requirements. No tool allowlists,
network, permissions, credentials, trust, model policy, or output gates
change.

Added two assertions in the existing registration test suite protecting
both producer twins. Both failed on the old contradictory guidance and
pass after correction. Regenerated both locks with retained **gh-aw
v0.86.2**, without manual edits or compiler upgrade; **only `body_hash`
changes**. Frontmatter and all generated lock runtime content remain
identical.

Additional exact validation commands and results:

```powershell
pwsh -NoProfile -Command '$env:PSModulePath = "/Users/shneuvil/.copilot/session-state/237fbb01-6532-4170-9f5e-6af14fa3a5e0/files/powershell-modules" + [IO.Path]::PathSeparator + $env:PSModulePath; Import-Module Pester -ErrorAction Stop; $config = New-PesterConfiguration; $config.Run.Path = @(".github/scripts/Register-CiFixSafeOutputExpectation.Tests.ps1", ".github/scripts/Test-CiFixTransport.Tests.ps1", ".github/scripts/Queue-CiFixAzdoValidation.Tests.ps1"); $config.Run.Exit = $true; $config.Output.Verbosity = "Normal"; $config.TestResult.Enabled = $true; $config.TestResult.OutputPath = "/Users/shneuvil/.copilot/session-state/1e0cc90a-a521-4055-9e7a-9565cdaf5504/files/producer-and-dispatcher-pester-results.xml"; Invoke-Pester -Configuration $config'
# Passed after lock regeneration: 116 tests (6 registration, 31 transport, 79 dispatcher); 0 failed/skipped.

pwsh -NoProfile -Command '$file = Join-Path $PWD ".github/scripts/Register-CiFixSafeOutputExpectation.Tests.ps1"; $tokens = $null; $errors = $null; [void][System.Management.Automation.Language.Parser]::ParseFile($file, [ref]$tokens, [ref]$errors); if ($errors.Count) { $errors | ForEach-Object { Write-Error $_ }; exit 1 }; Write-Output "PowerShell parse passed"'
# Passed.
```

```bash
/Users/shneuvil/.copilot/session-state/237fbb01-6532-4170-9f5e-6af14fa3a5e0/files/tools/gh-aw-0.86.2/darwin-arm64 compile ci-status-fix ci-status-fix-net11 --strict --no-emit --no-check-update
# Passed: 2 workflows, 0 warnings.
/Users/shneuvil/.copilot/session-state/237fbb01-6532-4170-9f5e-6af14fa3a5e0/files/tools/gh-aw-0.86.2/darwin-arm64 compile ci-status-fix ci-status-fix-net11 --strict --no-check-update
# Passed: 2 workflows, 0 warnings; emitted body-hash-only changes.
actionlint .github/workflows/ci-status-fix.lock.yml .github/workflows/ci-status-fix-net11.lock.yml
# Nonzero both before and after regeneration: identical six baseline diagnostics.
# Each twin: concurrency.queue not recognized, ShellCheck SC2129 style, github.aw expression not recognized.
# No new lint findings; baseline/after outputs compared byte-identical.
```

**Producer limits:** These are static prompt/configuration assertions
and offline helper tests, not a hosted agent behavior evaluation.
Removing the contradiction does not guarantee that an agent will
register correctly, find a viable product fix, create a PR, or attach
Azure checks. Separate cited-timeline failures and other producer
blockers are not fixed here. No live workflow or network validation
tests were run.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

Follow-up to dotnet#39147 for the production startup regression evidenced by
the two linked dispatcher runs, plus the separate pre-existing producer
helper-guidance contradiction evidenced by the two producer runs. No
separate tracking issue is closed by this PR.

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

---------

Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1e0cc90a-a521-4055-9e7a-9565cdaf5504
Updated
[Microsoft.AspNetCore.Authentication.Facebook](https://github.com/dotnet/dotnet)
from 10.0.0 to 10.0.13.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.AspNetCore.Authentication.Facebook's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.AspNetCore.Authentication.Google](https://github.com/dotnet/dotnet)
from 10.0.0 to 10.0.13.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.AspNetCore.Authentication.Google's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.AspNetCore.Authentication.MicrosoftAccount](https://github.com/dotnet/dotnet)
from 10.0.0 to 10.0.13.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.AspNetCore.Authentication.MicrosoftAccount's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
@sheiksyedm

Copy link
Copy Markdown
Contributor

/azp run maui-pr-uitests , maui-pr-devicetests

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).

kubaflo and others added 8 commits October 7, 2026 19:56
…otnet#39201)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

<!-- Enter description of the fix in this section -->

Make `/issue triage` apply real evidence-backed issue labels without
publishing this workflow's explanation comments, including withheld-only
reports. Existing label writes were already working; this corrects the
unwanted additional public reports, not the labeling API.

Preserve the single `add_comment` + `data.triage` intent as internal
typed evidence transport. After all existing validation, legacy
report-marker/fingerprint reconciliation, final complete
snapshot/authority recheck and artifact retention, trusted code now
always removes that comment intent and releases only the exact validated
`add_labels`/`remove_labels` intents. A validated withheld-only proposal
emits one native `noop` with a nonempty `message`, not an empty output
array. `noop.report-as-issue: false` remains explicit.

`report.md` and `decision.json` remain retained in Actions artifacts.
`validation.json` also records `publicCommentWrites: 0` and the
requested additions/removals; these are requested deltas, not
completed-write claims. Update the workflow prompt, structured-output
skill and command documentation consistently, and regenerate only
`issue-triage.lock.yml` using pinned gh-aw v0.86.2. No shared-import
changes, new handlers, credentials, global staging, product changes,
synthetic production fixtures or new CI tests.

All provenance, authority, exact label-delta, bounds, freshness,
incomplete/error and native threat-detection checks are preserved.
Legacy public reports remain excluded from evidence. This does not
delete existing comments or alter separate Policy Service replies
triggered by feedback labels.

**Validation commands and results**

- `gh aw compile issue-triage --strict --no-check-update` — passed with
gh-aw v0.86.2, one workflow compiled, zero warnings; only the expected
body-hash metadata changed in the lock.
- `gh aw hash-frontmatter .github/workflows/issue-triage.md` — passed;
actual hash equals compiled metadata:
`eb116514f337eb247c8767becceaefdd9cfb69da65044098b5cdc510e7c2d153`.
- `actionlint -ignore '^unexpected key "queue" for "concurrency"
section\. expected one of "cancel-in-progress", "group"$'
.github/workflows/issue-triage.lock.yml` — passed with actionlint
v1.7.12 and only its known `queue: max` compatibility exception.
- PowerShell `[System.Management.Automation.Language.Parser]::ParseFile`
on `.github/scripts/IssueTriage.ps1` — passed, no parse errors; ten
existing literal regex patterns also compiled successfully.
- `git diff --check` — passed.
- `gh workflow run issue-triage.lock.yml --repo dotnet/maui --ref main
-f issue_number=39187 -f staged=true` — hosted run
[37542331564](https://github.com/dotnet/maui/actions/runs/37542331564)
succeeded and produced genuine raw structured evidence for seven
additions. Updated local `Validate` against its complete immutable
context and fresh upstream reads passed; the emitted output contains
exactly one `add_labels` intent with all seven original strings and
**zero `add_comment` intents**. All three report artifacts are retained.
- `gh workflow run issue-triage.lock.yml --repo dotnet/maui --ref main
-f issue_number=39169 -f staged=true` — final fresh hosted run
[37544034144](https://github.com/dotnet/maui/actions/runs/37544034144)
succeeded and produced a genuine withheld-only proposal. Updated local
`Validate` passed with its original complete context and fresh upstream
reads; emitted exactly one native `noop`, **zero comments**, and
retained the exact original decisions/report/audit. `Test-Json` against
the pinned v0.86.2 native noop input schema passed.
- `gh workflow run issue-triage.lock.yml --repo dotnet/maui --ref main
-f issue_number=39182 -f staged=true` — hosted run
[37543380202](https://github.com/dotnet/maui/actions/runs/37543380202)
produced a genuine pure noop. Updated local validation passed and
preserved its raw output byte-for-byte.
- Direct `Validate` with genuine raw dotnet#39187 evidence and an
intentionally mismatched `-ExpectedContextHash` — rejected before
publication with the independently prepared context-binding error; raw
evidence remained unchanged and no success artifact was written.
Stale/incomplete gates remain unchanged; no fabricated stale or
incomplete model-output fixtures were executed.

For the withheld-only local replay, `EVIDENCE` points to the retained
downloaded artifact root, and `publication-output.json` is a copy of the
immutable raw `agent/agent_output.json`:

```bash
pwsh -NoProfile -File .github/scripts/IssueTriage.ps1 \
  -Stage Validate -IssueNumber 39169 -Actor kubaflo \
  -ContextDirectory "$EVIDENCE/run-39169-final/issue-triage-context-37544034144" \
  -OutputDirectory "$EVIDENCE/run-39169-final/local-report" \
  -ExpectedContextHash 1704D56200E8516A642C2E9C3751B0045724294A9AAF2EDFF3A21C131C7C1F39 \
  -AgentOutputPath "$EVIDENCE/run-39169-final/publication-output.json"
```

Result: passed, `Validated 0 additions and 0 removals`, with:

```json
{"items":[{"type":"noop","message":"No label changes requested; validated withheld decisions are retained in the issue-triage-report artifact."}],"errors":[]}
```

The positive replay used the same `Validate` command with issue `39187`,
its `issue-triage-context-37542331564` artifact and original hash
`8DE30358F2475D90E11E7A02AB7B202D1803AC00FBF8977A912EAEDFA30F7F69`. It
retained `area-controls-collectionview`, `platform/ios`,
`collectionview-cv2`, `version/iOS-26`, `has-workaround`,
`potential-regression` and `s/needs-verification` unchanged.

These hosted runs collected staged proposals from deployed main
`7d38fd06d059c4875bd81690c360a196aae26a26`; the changed validator was
exercised locally on their genuine raw outputs, not on rendered output
or rebound stale contexts. They did not apply labels or post comments.
Human merge and fresh production revalidation are still required.
Existing warnings about release tags without recognized framework
versions were surfaced normally and were not suppressed.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

No linked issue. User-directed correction: `/issue triage` should add
real labels, not post explanation comments.

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…9235)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

<!-- Enter description of the fix in this section -->

Focused follow-up to dotnet#39201: collapse only the exact successfully
handled `/issue triage` invocation comment using GitHub's `RESOLVED`
classifier, matching the existing `/issue trace-regression` experience.
Label explanations remain Actions-artifact-only; no public triage report
or status comments are restored. Native custom-job failure reports are
explicitly disabled so completion failures cannot create public report
noise.

A separate fresh hosted completion job uses trusted `github.sha` tooling
and step-scoped `GITHUB_TOKEN`. It requires successful
activation/agent/detection/native safe-output processing, positive
matching native operation counts, and zero
cancelled/deferred/failed/skipped/warning items. An explicitly
successful detector verdict is required; its legitimate no-op skip is
accepted only with a trusted `noop` validation receipt. The retained
validator receipt binds the operation count, issue, requester,
triggering comment, context hash, run ID and first attempt. Validated
no-change and withheld-only native no-ops are supported.

Completion also verifies actual label postconditions: every exact
canonical name in the trusted validated additions must be present, and
every requested removal absent, in the freshly fetched issue label
objects. It rejects malformed label arrays/objects, duplicate or
opposing requested names, and operation-count mismatches. Pure no-op
receipts explicitly retain empty addition/removal arrays. This closes
the pinned v0.86.2 removal handler's false-success gap (`success: true`
can coexist with `failedLabels`, which native item status does not
classify as failure). This is a point-in-time postcondition check:
malformed or unmet label state detected in that fetched snapshot leaves
the command visible. The subsequent command checks and separate
minimization mutation are not atomic with the label read, so a
concurrent label change after that snapshot can still occur before the
command collapses. Completion never mutates or rolls back labels.

Before the fixed GraphQL mutation, trusted completion rechecks
default-branch infrastructure, current requester permission, the exact
open non-PR issue, comment association, human author/account ID,
comment/node IDs, exact body and creation/update timestamps.
Manual/staged invocations, bots, other commands/comments, edits and job
reruns cannot minimize a comment. Mutation failures or unconfirmed
results produce an explicit Actions warning without rolling back
successful labels. No agent permission, credential, model pin, shared
import or native WTD3 behavior changes.

Validation (gh-aw v0.86.2; rerun after the exact-outcome fix; no
pipeline tests or synthetic fixtures added):

- `gh aw compile issue-triage --strict --no-check-update` — passed, one
workflow, zero warnings; generated lock reviewed and unchanged by the
script/docs follow-up.
- `gh aw hash-frontmatter .github/workflows/issue-triage.md` — passed;
actual hash including current imports matches generated metadata:
`c848d6ca0861ac24b0a3d0286e6b6d49a2028ebde30f0b3680db1057823aa00b`.
- `pwsh -NoProfile -Command '$metadata = ((Get-Content
.github/workflows/issue-triage.lock.yml -TotalCount 1) -replace "^#
gh-aw-metadata: ", "") | ConvertFrom-Json; $hash = & gh aw
hash-frontmatter .github/workflows/issue-triage.md; if ($LASTEXITCODE
-ne 0 -or $hash.Trim() -cne $metadata.frontmatter_hash) { throw
"Frontmatter/import hash mismatch" }; "Compiled frontmatter/import hash
matches: $hash"'` — passed.
- `pwsh -NoProfile -Command '$tokens = $null; $errors = $null; $null =
[System.Management.Automation.Language.Parser]::ParseFile((Join-Path
$PWD ".github/scripts/IssueTriage.ps1"), [ref]$tokens, [ref]$errors); if
($errors.Count) { $errors | Format-List; exit 1 }; "Whole-script
PowerShell AST: passed"'` — passed.
- `actionlint -format '{{json .}}'
.github/workflows/issue-triage.lock.yml | jq -e 'length > 0 and all(.[];
.kind == "syntax-check" and (.message | test("^unexpected key \"queue\"
for \"concurrency\" section\\. expected one of \"cancel-in-progress\",
\"group\"$")))'` — passed the exact known compatibility-exception
filter. Raw actionlint reports only the two existing `queue: max`
incompatibilities; no other diagnostics.
- `git diff --check` — passed, including the subsequent
documentation-only point-in-time clarification. `test "$(git diff
--name-only)" = '.github/docs/issue-triage.md'` — passed before that
clarification commit, confirming no implementation or workflow
configuration changes. No compiler rerun or tests were needed for the
wording-only correction.

These are local syntax/configuration checks and pinned-source
inspection, not runtime tests or deployed end-to-end minimization
verification. No historical comments were hidden, real label runs
dispatched, or unmerged infrastructure deployed. Future live
verification requires merge and a separately bounded approved
command-testing scope.

### Issues Fixed

<!-- Please make sure that there is a bug logged for the issue being
fixed. The bug should describe the problem and how to reproduce it. -->

No separately filed issue. User-requested completion-UX follow-up to
dotnet#39201, including the partial-removal false-success finding raised
during review.

<!--
Are you targeting main? All PRs should target the main branch unless
otherwise noted.
-->
Updated [Microsoft.Web.WebView2](https://aka.ms/webview) from
1.0.3179.45 to 1.0.4258.31.

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Microsoft.Web.WebView2&package-manager=nuget&previous-version=1.0.3179.45&new-version=1.0.4258.31)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…39247)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

<!--
!!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING
MAIN. !!!!!!!
-->

### Description of Change

<!-- Enter description of the fix in this section -->

`BlazorWebViewHandler` subscribes to `RootComponents.CollectionChanged`
but does not unsubscribe when disconnected. When an Android Activity is
recreated with a cached Window and page, the page-owned collection
retains replaced handlers, their MauiContext, and the destroyed
Activity.

This change adds shared cleanup that removes the subscription and
releases the handler's collection reference without clearing the root
components. Cleanup runs before platform teardown in the Android,
iOS/MacCatalyst, Windows, and Tizen handlers.

The regression test verifies that disconnect removes the subscription,
preserves the root component, and allows the handler to reconnect with
exactly one subscription.

**Validation**

- Reproduced in Android Sandbox after two Activity recreations: both
replaced handlers remained subscribed and retained destroyed Activity
contexts.
- Repeated the same scenario with the fix: only the current handler
remained subscribed, and both replaced handlers were collected.
- Ran the full before/after verification gate: the regression test
failed without the fix at `Assert.Empty` because the subscription
remained, and passed with the fix.
- MacCatalyst build passed with 0 warnings and 0 errors.
- Broader Android tests reported 39 passed, 4 failed, and 4 skipped. The
failing path-resolution and back-navigation tests also failed with the
Android fix removed.

Other Activity retention remained visible in Sandbox. This change fixes
the reported handler subscription path, not every possible Activity
retention source. Windows and Tizen builds and Apple runtime tests were
not run.

Fixes dotnet#39227

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Address the explicit-None tracking behavior and add coverage for page- and scroll-view-owned safe areas.

1 open finding

🧠 Review effort: Lite

Comment thread src/Core/src/Platform/Android/SafeAreaExtensions.cs
@vishnumenon2684

Copy link
Copy Markdown
Contributor

/azp run maui-pr-uitests , maui-pr-devicetests

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 2 pipeline(s).

@kubaflo

This comment has been minimized.

@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Note

🔍 /review started

AzDO build 15628026 is running for android.

The s/agent-review-in-progress label stays on this PR while the run is active. The final recommendation and outcome labels are posted only after Gate, expert review, and Deep UI tests finish.

@kubaflo

This comment has been minimized.

@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Tests Failure Analysis

@praveenkumarkarunanithi — test-failure analysis for commit 0e3b59a.

Scope CI failures Commit 0e3b59a


🧪 CI Analysis — click to expand
📊 maui-pr

**Insufficient (redacted) five partial main histories; no comparable install diagnostic.


🧪 maui-pr-devicetests

🧪 maui-pr-uitests

**Insufficient (redacted) pending; ScrollView/Android Shell timed out; current/five target histories truncated.


🧭 Follow-up — actions and refresh

Next action: Wait for UI completion; restore evidence and investigate unresolved diagnostics.

Maintainers: comment /review tests to refresh this report.

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please check if test failures are related?

@praveenkumarkarunanithi

Copy link
Copy Markdown
Contributor Author
  • maui-pr-uitests (Android UITests SafeAreaEdges (API 36 Pixel 3 XL) Controls SafeAreaEdges (API 36 Pixel 3 XL))

@kubaflo, the failures are not related to this PR.

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review Summary

@praveenkumarkarunanithi — new AI review results are available based on commit 0e3b59a.

Gate Failed Confidence Low Platform Android


🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix

Gate Result: ❌ FAILED

Platform: ANDROID · Base: main · Merge base: 45bab995

🩺 Fix does not pass the tests — every test still fails after applying the fix. The PR's change does not resolve the failure(s).

Test Without Fix (expect FAIL) With Fix (expect PASS)
🖥️ Issue36269 Issue36269 ✅ FAIL — 2747s ❌ FAIL — 1816s
🔴 Without fix — 🖥️ Issue36269: FAIL ✅ · 2747s

Error-relevant lines (filtered from the build log):

/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.115/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.115/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Mono.AndroidTools.AndroidDevice.<>c__DisplayClass105_0.<InstallPackage>b__0(Task`1 t) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.115/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.115/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: --- End of stack trace from previous location --- [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.115/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.115/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.115/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.115/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.RunInstall() [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
Build FAILED.
     at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 299
   at Microsoft.Maui.TestCases.Tests.Issues.Issue36269.SafeAreaBottomPaddingIsAppliedWhenTabBarHiddenAtRuntime() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue36269.cs:line 23
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
   at Microsoft.Maui.TestCases.Tests.Issues.Issue36269.SafeAreaBottomPaddingIsRemovedWhenTabBarShownAgain() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue36269.cs:line 37
🟢 With fix — 🖥️ Issue36269: FAIL ❌ · 1816s

Error-relevant lines (filtered from the build log):

     at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 299
   at Microsoft.Maui.TestCases.Tests.Issues.Issue36269.SafeAreaBottomPaddingIsAppliedWhenTabBarHiddenAtRuntime() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue36269.cs:line 23
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
   at Microsoft.Maui.TestCases.Tests.Issues.Issue36269.SafeAreaBottomPaddingIsRemovedWhenTabBarShownAgain() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue36269.cs:line 37

⚠️ Failure Details

  • ❌ Issue36269 FAILED with fix (should pass)
    • SafeAreaBottomPaddingIsAppliedWhenTabBarHiddenAtRuntime [8 s]; SafeAreaBottomPaddingIsRemovedWhenTabBarShownAgain [5 s]
    • VisualTestUtils.VisualTestFailedException : Baseline snapshot not yet created: /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/snapshots/android/SafeAreaBottomPadding...; VisualTestUtils.VisualTestFailedException : Baseline snapshot not yet created: /home/vsts/work...
📁 Fix files reverted (4 files)
  • src/Core/src/Platform/Android/ContentViewGroup.cs
  • src/Core/src/Platform/Android/LayoutViewGroup.cs
  • src/Core/src/Platform/Android/MauiScrollView.cs
  • src/Core/src/Platform/Android/SafeAreaExtensions.cs

📋 Pre-Flight — Context & Validation

Pre-Flight Context

Scope: Context gathering only for #36474. This is not an exhaustive review, implementation assessment, or recommendation. No tests were rerun and no files were changed.

PR and issue context

  • PR: #36474, open and currently blocked.
  • Submitted range: d356b4b73ff7641d0ec5304fb92ad7de0958aed0 → 0e3b59ab0a2f081544bc7055cc7bdbe2c76cc525.
  • Size: 15 changed files, 178 additions, 3 deletions.
  • Linked issue: #36269, an Android regression assigned to the .NET 10 SR12 milestone.
  • Reported behavior: With a Shell containing two tabs, SafeAreaEdges="All" can lose its bottom padding after one page hides the TabBar and the user navigates between tabs repeatedly. Content then extends behind the Android bottom navigation area.
  • Reported environment: Android 16; reported in MAUI 10.0.80 and independently reproduced starting in 10.0.70, but not 10.0.60. The reporter identifies 9.0.120 SR12 as previously working.
  • Reported workaround: Raising OnPropertyChanged(nameof(SafeAreaEdges)) after a size allocation forces safe-area recalculation.

The PR attributes the regression to #34324. That earlier merged change handles a Gone → Visible Android Shell TabBar transition by posting ViewCompat.RequestApplyInsets for the displayed page after layout, fixing #33703’s stale-padding/empty-space scenario. The current PR reports that this dispatch can occur while another Shell page temporarily has reduced bounds, causing that page’s bottom padding to become zero; when it later expands, a normal resize does not itself dispatch insets, leaving the zero padding stale.

Submitted mechanism

The functional changes are Android-only and introduce no public API:

  • src/Core/src/Platform/Android/ContentViewGroup.cs
  • src/Core/src/Platform/Android/LayoutViewGroup.cs
  • src/Core/src/Platform/Android/MauiScrollView.cs
  • src/Core/src/Platform/Android/SafeAreaExtensions.cs

Previously, each affected OnLayout path requested insets only when _didSafeAreaEdgeConfigurationChange was set and an inset listener was installed. The submitted change also requests insets when Android reports changed layout bounds and ShouldReapplyInsetsForResize(...) says the view is eligible.

The new internal eligibility helper returns true when either:

  1. The cross-platform view explicitly configured SafeAreaEdges, and at least one edge requests a region other than None or SoftInput-only; or
  2. MauiWindowInsetListener already tracks the native view.

Relevant existing source behavior:

  • HandleWindowInsets delegates to SafeAreaExtensions.ApplyAdjustedSafeAreaInsetsPx.
  • A view is added to the listener’s tracked-view set only after nonzero safe-area padding is applied.
  • Consequently, the explicit-configuration branch can include an opted-in view whose current padding is zero, while the tracked branch preserves recalculation for a view that previously received padding.
  • SoftInput-only explicit edges are excluded while untracked; mixed edge regions containing more than SoftInput are not excluded.
  • ContentViewGroup does not install its own listener when directly hosted by MauiScrollView; the scroll view handles that path.
  • The trigger is general eligible-view resizing, not specifically Shell navigation, so the affected runtime surface includes any size-changing Android layout involving these three native view types.

Test and snapshot changes

Two source files add the regression fixture:

  • src/Controls/tests/TestCases.HostApp/Issues/Issue36269.cs
    • Creates a two-item Shell TabBar.
    • Places SafeAreaEdges.All on a Grid.
    • Provides buttons that directly hide and show the TabBar at runtime.
    • Uses a visible bottom bar and BottomEdgeLabel for screenshot comparison.
  • src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue36269.cs
    • Compiles under ANDROID || IOS.
    • Adds one screenshot test after hiding the TabBar and another after hiding then showing it.
    • Waits for existing elements and uses a two-second screenshot retry timeout.

Nine binary snapshot files change:

  • Two new Android API-36 notch snapshots for the new tests.
  • Four new iOS snapshots for the new tests (ios and ios-26).
  • Three existing generic Android snapshots are modified:
    • EditorPlaceholderRuntimeTextAlignmentChanged.png
    • EditorRuntimeTextAlignmentChanged.png
    • NavBarHidden.png

The immutable binary diff exposes only file identities and hashes, so the visual differences and whether the three existing Android baseline updates are expected cannot be established from this context. No iOS runtime implementation changes are submitted, despite adding iOS coverage. Catalyst and Windows are excluded in the test source.

Platform-sensitive validation requirements

The designated validation platform is Android. Relevant evidence would need to establish:

  • The original Android 16/API-36 scenario with two Shell tabs, repeated navigation, SafeAreaEdges.All, and runtime TabBar visibility changes.
  • Correct bottom padding both when the page expands after hiding the TabBar and when it contracts after showing the TabBar.
  • Preservation of #34324/#33703 behavior so showing the TabBar does not restore the earlier empty-space regression.
  • Execution and expected screenshot behavior of both new Android tests, including confirmation that their direct hide/show sequence represents the reported repeated tab-navigation lifecycle.
  • Behavior across ContentViewGroup, LayoutViewGroup, and MauiScrollView.
  • Explicit SafeAreaEdges.None, default/container behavior, SoftInput-only edges, mixed SoftInput regions, keyboard transitions, and views moving between zero and nonzero padding.
  • Whether resize-triggered RequestApplyInsets causes excessive dispatches, layout churn, or inset/layout feedback during animations and ordinary resizing.
  • Compatibility with #35664’s listener gating for recycler descendants, particularly explicit opt-in views and already-tracked views.
  • Justification for the three modified pre-existing Android snapshots and the iOS baselines.

Validation state and uncertainties

  • Gate result supplied for this experiment: Gate ❌ FAILED — tests did NOT behave as expected. It was not rerun.
  • The supplied Gate statement does not identify which test failed, whether the new regression tests ran, or whether failure occurred before or after the functional assertion; those details remain unknown.
  • A separate PR test-failure report for head 0e3b59a records unresolved Android evidence, including an API-36 SafeAreaPerEdgeValidation/Issue28986 SoftInput assertion requiring investigation and Android Shell/ScrollView UI lanes that timed out or had truncated history. It does not establish the disposition of the new #36269 tests.
  • The PR description claims Android and iOS behavior was tested, but the exact devices, OS versions, runs, and results are not available in the submitted diff.
  • The new fixture directly toggles TabBar visibility on one page; the issue reproduction navigates between tabs repeatedly. Whether both exercise the same transient Shell pager sizing sequence remains unknown.
  • There are no submitted focused unit or device tests for ShouldReapplyInsetsForResize, its SoftInput filtering, listener tracking transitions, or dispatch frequency.
  • Binary screenshot contents were unavailable for visual inspection, so padding geometry and unrelated baseline changes remain unknown.
  • The effect of repeatedly requesting insets for every eligible changed layout, including performance and possible re-layout loops, is not established by available evidence.

🔬 Code Review — Deep Analysis

Expert PR Evaluation

Verdict: NEEDS_DISCUSSION
Confidence: low

Submitted-fix assessment

The single expert review evaluated the submitted range
d356b4b73ff7641d0ec5304fb92ad7de0958aed0...0e3b59ab0a2f081544bc7055cc7bdbe2c76cc525.
The Android change extends the existing layout-time inset request in
ContentViewGroup, LayoutViewGroup, and MauiScrollView to eligible views whose
bounds changed. Eligibility is limited to an explicit non-None,
non-SoftInput-only safe-area request or a native view already tracked by the window
inset listener.

The reviewer found no concrete, actionable defect on a changed line. The required
inline findings artifact was written as an empty JSON array, so there are 0 errors
and 0 warnings to refine.

Evidence limits

  • Gate: ❌ FAILED. Both submitted #36269 screenshot tests reached
    VerifyScreenshot with the fix, but validation stopped because the generic Android
    baseline snapshots were not present. The submitted Android snapshots are under
    android-notch-36, while the Gate looked under snapshots/android. The run
    therefore does not demonstrate the rendered result and independently vetoes
    approval.
  • The submitted UI tests exercise direct runtime hide/show operations, while the
    reported issue involves repeated Shell tab navigation and a transient pager resize.
    Available evidence does not prove those lifecycles are equivalent.
  • The submitted change runs for general eligible-view resizes, not only Shell
    navigation. No focused evidence establishes dispatch frequency, absence of
    inset/layout feedback during animation, or the negative cases for None,
    SoftInput-only, mixed edge regions, and tracked zero-padding transitions.
  • Three pre-existing Android snapshot baselines changed without reviewable visual
    evidence tying them to this fix.

Refinement threshold

Not met. The expert review identified no concrete actionable defect or unresolved
behavioral mechanism backed by source/test evidence. Producing a
pr-plus-reviewer patch would therefore be speculative and is intentionally skipped.


🛠️ Try-Fix — Analysis & Comparison

Alternative generation: not requested

Evidence-first mode intentionally omits routine Try-Fix attempts. This is not a failed
attempt, a completed alternative search, or evidence that alternatives have no value.
The expert review may still produce one evidence-backed PR refinement.


🏁 Report — Final Recommendation

⚠️ Final Recommendation: REQUEST CHANGES

Phase Status

Phase Status Notes
Pre-Flight ✅ COMPLETE Trusted evidence-first context consumed
Expert Review NEEDS_DISCUSSION (low confidence) 0 errors, 0 warnings; no concrete changed-line defect
Gate ❌ FAILED Android; both with-fix screenshot tests failed because the expected generic Android baselines were absent
Try-Fix not requested Intentional evidence-first omission; TRY-FIX-STATUS: not-requested
Refinement NOT GENERATED Expert evidence did not meet the source/test-backed refinement threshold
Report ✅ COMPLETE

Code Review and Candidate Comparison

Rank Candidate Expert assessment Validation Result
1 pr No concrete actionable defect on a changed line; unresolved evidence warrants discussion ❌ FAILED — the new tests reached screenshot verification, but the Gate could not find generic Android baselines and therefore did not validate the rendered behavior Sole real candidate; not demonstrated merge-ready

Winner: pr
Selected Fix: PR

The submitted PR is the only implemented candidate. Routine Try-Fix alternatives were
not requested, and no pr-plus-reviewer refinement was justified by the expert
findings. Ranking the sole candidate first does not override the failed Gate or make it
ready for approval.

Summary

Request changes because the trusted Android Gate failed. The implementation is a
plausible, scoped response to stale overlap-based safe-area padding and the expert
review found no source-line error, but the submitted tests supplied no usable Gate
comparison: both stopped at missing generic Android snapshot baselines. The original
repeated Shell tab-navigation lifecycle, preservation of #34324/#33703 behavior, and
negative resize/inset cases therefore remain unvalidated.

Root Cause

#34324 added an inset request when a Shell TabBar returns from hidden to visible. In
the reported lifecycle, that request can run while the shared Shell page is temporarily
shorter, recalculating its bottom safe-area padding to zero. Android does not ordinarily
reapply insets when the page later returns to full height, so the zero padding remains
stale.

Fix Quality

The submitted change re-requests insets after a changed layout for an explicitly
configured safe-area view or a view already tracked by the inset listener. It covers
ContentViewGroup, LayoutViewGroup, and MauiScrollView, and excludes untracked
default, None, and SoftInput-only configurations from the added hot path. Mechanical
regression analysis found overlap with #35234 in the three layout types but no exact
line revert.

The available validation is insufficient: the Gate failed before visual comparison,
the tests directly hide/show the TabBar rather than reproduce repeated cross-tab
navigation, and there is no focused evidence for dispatch frequency, layout feedback,
mixed safe-area regions, or the prior empty-space regression. Those gaps must be
resolved without treating the missing snapshot lookup as a behavioral pass.


🔗 Regression Cross-Reference

🔍 Regression Cross-Reference

⚠ Overlaps with prior bug-fix PRs — same files modified, but no exact line revert detected.

File Fix PR Fixed issue(s)
src/Core/src/Platform/Android/ContentViewGroup.cs #35234 #7580, #9095, #11402, #12916, #13243, #13801, #15806, #19560, #19690, #19866, #20028, #26103, #26366, #27554, #29529, #29772, #30192, #30199, #30254, #31658, #31799, #32971, #33065, #33241, #33334, #33373, #33500, #33615, #33767, #33783, #34101, #34257, #34266, #34402, #34504, #34551, #34611, #34662, #34671, #34716, #34755, #34759, #34771, #34772, #34842, #34846, #34848, #34861, #34889, #34892, #34897, #34898, #34900, #34917, #34925, #34953, #34975, #35005, #35018, #35063, #35116, #35119, #35125, #35127
src/Core/src/Platform/Android/LayoutViewGroup.cs #35234 #7580, #9095, #11402, #12916, #13243, #13801, #15806, #19560, #19690, #19866, #20028, #26103, #26366, #27554, #29529, #29772, #30192, #30199, #30254, #31658, #31799, #32971, #33065, #33241, #33334, #33373, #33500, #33615, #33767, #33783, #34101, #34257, #34266, #34402, #34504, #34551, #34611, #34662, #34671, #34716, #34755, #34759, #34771, #34772, #34842, #34846, #34848, #34861, #34889, #34892, #34897, #34898, #34900, #34917, #34925, #34953, #34975, #35005, #35018, #35063, #35116, #35119, #35125, #35127
src/Core/src/Platform/Android/MauiScrollView.cs #35234 #7580, #9095, #11402, #12916, #13243, #13801, #15806, #19560, #19690, #19866, #20028, #26103, #26366, #27554, #29529, #29772, #30192, #30199, #30254, #31658, #31799, #32971, #33065, #33241, #33334, #33373, #33500, #33615, #33767, #33783, #34101, #34257, #34266, #34402, #34504, #34551, #34611, #34662, #34671, #34716, #34755, #34759, #34771, #34772, #34842, #34846, #34848, #34861, #34889, #34892, #34897, #34898, #34900, #34917, #34925, #34953, #34975, #35005, #35018, #35063, #35116, #35119, #35125, #35127

📱 UI Tests — SafeAreaEdges,ViewBaseTests

Detected UI test categories: SafeAreaEdges,ViewBaseTests

[!WARNING]
No UI test results were produced for the detected categories. The platform-pool run
returned no results — most often because the PR build failed (see the Gate section) or
the deep UI test stage was skipped. Fix the build/gate issues and push again; the review
re-runs on new commits (a maintainer can also re-run it).


🧭 Next Steps — review latest findings

No alternative fix was selected for this run. Review the session findings and CI results before merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-safearea Issues/PRs that have to do with the SafeArea functionality community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/android s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-gate-failed AI could not verify tests catch the bug s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Android] SafeAreaEdges break with tab navigation and Shell.TabBarIsVisible="False"

8 participants