Skip to content

[iOS] Alert popup may be displayed on wrong window when modal page navigation is in progress - fix#31016

Merged
kubaflo merged 1 commit intodotnet:inflight/currentfrom
kubaflo:fix-30970
Mar 26, 2026
Merged

[iOS] Alert popup may be displayed on wrong window when modal page navigation is in progress - fix#31016
kubaflo merged 1 commit intodotnet:inflight/currentfrom
kubaflo:fix-30970

Conversation

@kubaflo
Copy link
Copy Markdown
Contributor

@kubaflo kubaflo commented Aug 5, 2025

Description of Change

By skipping view controllers that are being dismissed (animation is happening, for example ), we ensure DisplayAlert() and other popups are shown only on valid, active UI stacks, preventing the deadlock and improving reliability on iOS/macOS.

Issues Fixed

Fixes #30970

Copilot AI review requested due to automatic review settings August 5, 2025 00:07
@kubaflo kubaflo requested a review from a team as a code owner August 5, 2025 00:07
@kubaflo kubaflo requested review from mattleibow and rmarinho August 5, 2025 00:07
@kubaflo kubaflo self-assigned this Aug 5, 2025
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes an iOS-specific issue where alert popups could be displayed on wrong windows during modal page navigation, potentially causing deadlocks. The fix prevents alerts from being presented on view controllers that are currently being dismissed.

  • Adds condition to skip view controllers that are being dismissed when finding the top view controller
  • Includes comprehensive test coverage with both HostApp UI and automated test cases
  • Targets iOS platform specifically where this navigation timing issue occurs

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/Controls/src/Core/Platform/AlertManager/AlertManager.iOS.cs Core fix that checks IsBeingDismissed property before traversing to presented view controllers
src/Controls/tests/TestCases.HostApp/Issues/Issue30970.cs UI test page that reproduces the modal navigation scenario with alert display
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30970.cs Automated test that validates the alert popup appears correctly after modal dismissal

protected override async void OnAppearing()
{
base.OnAppearing();
if (_modalPageWasShown)
Copy link

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

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

Accessing Application.Current.Windows[0] could throw an IndexOutOfRangeException if no windows exist. Consider checking if the Windows collection has items before accessing the first element.

Suggested change
if (_modalPageWasShown)
if (_modalPageWasShown && Application.Current.Windows.Count > 0)

Copilot uses AI. Check for mistakes.
{
base.OnAppearing();
if (_modalPageWasShown)
await Application.Current.Windows[0].Page!.DisplayAlert("My alert", "Can you see this alert?", "Yes");
Copy link

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

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

The null-forgiving operator ! on Page suggests potential null values. Consider using null-conditional operator or explicit null check for better error handling.

Suggested change
await Application.Current.Windows[0].Page!.DisplayAlert("My alert", "Can you see this alert?", "Yes");
{
var page = Application.Current.Windows[0].Page;
if (page != null)
{
await page.DisplayAlert("My alert", "Can you see this alert?", "Yes");
}
}

Copilot uses AI. Check for mistakes.
@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label Aug 5, 2025
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Hey there @@kubaflo! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@github-actions
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://github.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 31016

Or

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

Copy link
Copy Markdown
Contributor

@StephaneDelcroix StephaneDelcroix left a comment

Choose a reason for hiding this comment

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

Multi-Model Consensus Review (5 models: claude-opus-4.6 ×2, claude-sonnet-4.6, gemini-3-pro-preview, gpt-5.3-codex)

CI Status: ✅ All checks passing

Consensus Findings

No consensus bugs found. The fix is narrowly scoped to iOS/macOS only.

The PR adds an IsBeingDismissed guard in AlertManager.iOS.cs to skip view controllers that are in the process of being dismissed when searching for the top VC to present alerts on. This prevents alerts from being shown on a VC that is mid-dismiss, which could cause deadlocks or the alert appearing on the wrong window. Checking IsBeingDismissed before traversing to PresentedViewController is the standard iOS pattern for this scenario.

Test Coverage

✅ Includes both a TestCases.HostApp UI page (Issue30970.cs) and corresponding NUnit test (Issue30970.cs). Coverage is appropriate for the platform-specific scenario.

Verdict: ✅ Approve

Correct, minimal iOS fix using standard UIKit pattern.

@MauiBot MauiBot added s/agent-review-incomplete AI agent could not complete all phases (blocker, timeout, error) s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Mar 25, 2026
@dotnet dotnet deleted a comment from MauiBot Mar 26, 2026
@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented Mar 26, 2026

🤖 AI Summary

📊 Expand Full Review6d8ae5c · fix 30970
🔍 Pre-Flight — Context & Validation

Issue: #30970 - Alert popup may be displayed on wrong window when modal page navigation is in progress on iOS/MacOS
PR: #31016 - [iOS] Alert popup may be displayed on wrong window when modal page navigation is in progress - fix
Platforms Affected: iOS, macOS (Mac Catalyst)
Files Changed: 1 implementation, 2 test

Key Findings

  • Bug: DisplayAlert() causes a deadlock on iOS/macOS when called after popping a modal page. The alert is presented on a view controller that is in the process of being dismissed (still in the UIKit hierarchy but IsBeingDismissed == true), resulting in the alert never appearing and the awaited task never completing.
  • Root cause: GetTopUIViewController() in AlertManager.iOS.cs traverses PresentedViewController without checking if the view controller is being dismissed.
  • Fix: Add !topUIViewController.PresentedViewController.IsBeingDismissed guard to the while loop condition — stops traversal at a view controller being dismissed so presentation happens on a valid, active view controller.
  • Test added: UI test Issue30970 opens a modal page, closes it, and verifies that DisplayAlert appears afterward.
  • Copilot inline review suggested null safety improvements for Application.Current.Windows[0].Page! in the HostApp test page.
  • The PlatformAffected attribute in the HostApp page only specifies iOS (not macOS), though the issue and PR description mention both iOS and macOS.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #31016 Skip PresentedViewController that has IsBeingDismissed == true in GetTopUIViewController() loop ⏳ PENDING (Gate) AlertManager.iOS.cs Simple 1-line guard; stops traversal at dismissing VCs

🚦 Gate — Test Verification

Gate Result: ✅ PASSED

Platform: iOS

# Type Test Name Filter
1 UITest Issue30970.PopupShouldBeDisplayed Issue30970
Step Expected Actual Result
Without fix FAIL FAIL (TimeoutException, WaitForElement("Can you see this alert?") timed out after 16s)
With fix PASS PASS (1s, Test Run Successful, Passed: 1)

🔧 Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix (claude-opus-4.6) TransitionCoordinator guard: stop traversal if GetTransitionCoordinator() != null ✅ PASS 1 file More general than IsBeingDismissed — catches all mid-transition VCs
2 try-fix (claude-sonnet-4.6) Break-inside-loop with IsBeingDismissed || IsBeingPresented check ✅ PASS 1 file Two-directional guard; more defensive than PR fix
3 try-fix (gpt-5.3-codex) Call-site validation: ViewIfLoaded?.Window != null check in PresentPopUp ❌ FAIL 1 file Approach too late — presenter not exposed at call site; TimeoutException
4 try-fix (gemini-3-pro-preview) Backtracking: traverse to leaf VC, then backtrack via PresentingViewController if IsBeingDismissed ✅ PASS 1 file Two-pass approach; finds deepest stable VC
5 try-fix (claude-opus-4.6, cross-poll R1) TransitionCoordinator deferral: present after dismiss animation completes via AnimateAlongsideTransition ✅ PASS 1 file Most complex; preserves original VC traversal unchanged
6 try-fix (gpt-5.3-codex, cross-poll R2) Per-hop multi-guard: IsViewLoaded && View.Window != null && !IsBeingDismissed && !IsBeingPresented ✅ PASS 1 file Most thorough validity check per traversal hop
PR PR #31016 Skip PresentedViewController with IsBeingDismissed == true ✅ PASSED (Gate) 1 file Simple, targeted

Cross-Pollination

Model Round New Ideas? Details
claude-opus-4.6 1 Yes TransitionCoordinator deferral via AnimateAlongsideTransition
claude-sonnet-4.6 1 Yes Same TransitionCoordinator deferral idea
gpt-5.3-codex 1 Yes TransitionCoordinator deferral/enqueue
gemini-3-pro-preview 1 Yes TransitionCoordinator deferral
claude-opus-4.6 2 Yes Dedicated UIWindow at UIWindowLevel.Alert (bypasses VC chain)
claude-sonnet-4.6 2 No NO NEW IDEAS
gpt-5.3-codex 2 Yes Per-hop IsViewLoaded && View.Window != null (run as Attempt 6)
claude-opus-4.6 3 No NO NEW IDEAS — all strategy categories covered
gpt-5.3-codex 3 Yes Check presented.ViewIfLoaded?.Window == platformWindow (same window check)
gemini-3-pro-preview 3 Yes TransitionCoordinator.GetViewController(ToViewControllerKey)

Exhausted: Yes (max 3 rounds reached)
Selected Fix: PR #31016 — Simplest, most targeted fix (single !IsBeingDismissed guard). All 5 passing alternatives are valid but more complex without being meaningfully more robust for this specific bug. The PR's fix directly addresses the root cause with minimal code change.


📋 Report — Final Recommendation

✅ Final Recommendation: APPROVE

Phase Status

Phase Status Notes
Pre-Flight ✅ COMPLETE Issue #30970, iOS/macOS, 1 fix file + 2 test files
Gate ✅ PASSED iOS — tests FAIL without fix, PASS with fix
Try-Fix ✅ COMPLETE 6 attempts: 5 passing, 1 failing; 3 cross-poll rounds
Report ✅ COMPLETE

Summary

PR #31016 fixes a deadlock in DisplayAlert() on iOS/macOS when called after closing a modal page. The fix is a minimal, targeted 1-line change to GetTopUIViewController() in AlertManager.iOS.cs. A UI test was added to prevent regression. Gate verification confirmed the test correctly catches the bug and passes with the fix. 6 alternative approaches were explored: 5 passed but all were more complex with no clear benefit for this specific bug.

Root Cause

GetTopUIViewController() traverses PresentedViewController chain without checking if any VC in the chain is mid-dismissal (IsBeingDismissed == true). When DisplayAlert() is called during/immediately after PopModalAsync(), the dismissing modal's VC is still in the hierarchy but its view is detached from the window, causing PresentViewControllerAsync to present on an invalid host — the alert never appears and the awaited task deadlocks.

Fix Quality

The fix is excellent: minimal, correct, and well-tested. Adding !topUIViewController.PresentedViewController.IsBeingDismissed to the traversal loop condition stops at the last stable VC before a dismissing one. The test covers the exact reported scenario (open modal → close modal → DisplayAlert). Copilot flagged a minor null-safety concern (Windows[0] indexing without bounds check) in the test's HostApp page that is worth addressing, but it doesn't affect correctness in the test context.


@MauiBot MauiBot added s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates and removed s/agent-review-incomplete AI agent could not complete all phases (blocker, timeout, error) labels Mar 26, 2026
@kubaflo kubaflo changed the base branch from main to inflight/current March 26, 2026 21:27
@kubaflo kubaflo merged commit 08da508 into dotnet:inflight/current Mar 26, 2026
28 of 31 checks passed
PureWeen pushed a commit that referenced this pull request Apr 8, 2026
…vigation is in progress - fix (#31016)

### Description of Change

By skipping view controllers that are being dismissed (animation is
happening, for example ), we ensure DisplayAlert() and other popups are
shown only on valid, active UI stacks, preventing the deadlock and
improving reliability on iOS/macOS.

### Issues Fixed

Fixes #30970
devanathan-vaithiyanathan pushed a commit to devanathan-vaithiyanathan/maui that referenced this pull request Apr 9, 2026
…vigation is in progress - fix (dotnet#31016)

### Description of Change

By skipping view controllers that are being dismissed (animation is
happening, for example ), we ensure DisplayAlert() and other popups are
shown only on valid, active UI stacks, preventing the deadlock and
improving reliability on iOS/macOS.

### Issues Fixed

Fixes dotnet#30970
PureWeen pushed a commit that referenced this pull request Apr 14, 2026
…vigation is in progress - fix (#31016)

### Description of Change

By skipping view controllers that are being dismissed (animation is
happening, for example ), we ensure DisplayAlert() and other popups are
shown only on valid, active UI stacks, preventing the deadlock and
improving reliability on iOS/macOS.

### Issues Fixed

Fixes #30970
@PureWeen PureWeen mentioned this pull request Apr 14, 2026
devanathan-vaithiyanathan pushed a commit to Tamilarasan-Paranthaman/maui that referenced this pull request Apr 21, 2026
…vigation is in progress - fix (dotnet#31016)

### Description of Change

By skipping view controllers that are being dismissed (animation is
happening, for example ), we ensure DisplayAlert() and other popups are
shown only on valid, active UI stacks, preventing the deadlock and
improving reliability on iOS/macOS.

### Issues Fixed

Fixes dotnet#30970
Ahamed-Ali pushed a commit that referenced this pull request Apr 22, 2026
…vigation is in progress - fix (#31016)

### Description of Change

By skipping view controllers that are being dismissed (animation is
happening, for example ), we ensure DisplayAlert() and other popups are
shown only on valid, active UI stacks, preventing the deadlock and
improving reliability on iOS/macOS.

### Issues Fixed

Fixes #30970
PureWeen pushed a commit that referenced this pull request Apr 22, 2026
…vigation is in progress - fix (#31016)

### Description of Change

By skipping view controllers that are being dismissed (animation is
happening, for example ), we ensure DisplayAlert() and other popups are
shown only on valid, active UI stacks, preventing the deadlock and
improving reliability on iOS/macOS.

### Issues Fixed

Fixes #30970
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 26, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-controls-modal area-navigation NavigationPage community ✨ Community Contribution partner/syncfusion/review platform/ios platform/macos macOS / Mac Catalyst s/agent-approved AI agent recommends approval - PR fix is correct and optimal 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)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Alert popup may be displayed on wrong window when modal page navigation is in progress on iOS/MacOS

5 participants