Skip to content

[Android] Fix app hang when PopModalAsync called immediately after PushModalAsync#32853

Closed
Copilot wants to merge 2 commits intomainfrom
copilot/fix-app-hang-popmodal-issue
Closed

[Android] Fix app hang when PopModalAsync called immediately after PushModalAsync#32853
Copilot wants to merge 2 commits intomainfrom
copilot/fix-app-hang-popmodal-issue

Conversation

Copy link
Contributor

Copilot AI commented Nov 25, 2025

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!

Description of Change

Non-animated modals (animated: false) return control before the Android DialogFragment completes initialization. When PopModalAsync is called immediately after (e.g., with a single Task.Yield()), the pop operation fails silently, leaving a blank/hung screen.

// This hangs the app with a blank screen
await Navigation.PushModalAsync(new ContentPage(), animated: false);
await Task.Yield();
await Navigation.PopModalAsync();

Fix: Introduce PresentationCompleted event on ModalFragment that fires in OnStart() when the dialog is fully laid out. For non-animated modals, PresentModal now awaits this event before returning—mirroring how animated modals already wait for AnimationEnded.

  • Add PresentationCompleted event and FirePresentationCompleted() helper (follows existing FireAnimationEnded() pattern)
  • Fire in OnStart() after dialog.Window.SetLayout() completes
  • Safety fire in OnDestroy() to prevent deadlock if fragment destroyed early
  • Await PresentationCompleted for non-animated modals in PresentModal

Issues Fixed

Fixes #32310

Original prompt

This section details on the original issue you should resolve

<issue_title>App hangs if PopModalAsync is called after PushModalAsync with single await Task.Yield()</issue_title>
<issue_description>### Description

In any project, just add these three lines anywhere. After execution, the screen will be blank, even though it’s expected to remain on the same page we started from.

await Navigation.PushModalAsync(new ContentPage() { Content = new Label() { Text = "Hello!" } }, false);

await Task.Yield();

await Navigation.PopModalAsync();

In fact, this is a very serious bug, since any “unlucky” modal (popup) display completely freezes the entire application, blocking all input.

Also reproduces with Navigation.PopToRootAsync() instead of Navigation.PopModalAsync().

Found on Android API33-36, haven't tested on iOS

Here's what it looks like in the default project template:

private void OnCounterClicked(object? sender, EventArgs e)
        {
			Dispatcher.DispatchAsync(async () =>
			{
				await Navigation.PushModalAsync(new ContentPage() { Content = new Label() { Text = "Hello!" } }, false);

				await Task.Yield();

				await Navigation.PopModalAsync();
			});
		}

Current behavior (The app is blocked. Neither the previous page nor even the content of the modal is visible):

Screen_Recording_20251031_083406.mp4

Expected behavior (The modal appears and disappears quickly. There is a wait for two Task.Yield() here)

Screen_Recording_20251031_083439.mp4

Steps to Reproduce

  1. Add and call these three lines anywhere (for example, in the "Click me" button handler in the newly created MAUI project template in Visual Studio)
  2. The application is blocked with empty screen without any way to exit this state.

Link to public reproduction project repository

No response

Version with bug

9.0.110 SR12

Is this a regression from previous behavior?

No, this is something new

Last version that worked well

No response

Affected platforms

Android

Affected platform versions

Reproduced at least on Android 33, 36

Did you find any workaround?

No

Relevant log output

```</issue_description>

## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

….Yield

- Add PresentationCompleted event to ModalFragment to signal when modal is fully presented
- For non-animated modals, wait for PresentationCompleted before returning from PresentModal
- Fire PresentationCompleted in OnStart() when dialog window is fully laid out
- Add safety firing in OnDestroy() to prevent deadlocks if fragment is destroyed early
- Add test case Issue32310 to verify the fix

Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix app hang issue when calling PopModalAsync [Android] Fix app hang when PopModalAsync called immediately after PushModalAsync Nov 25, 2025
Copilot AI requested a review from PureWeen November 25, 2025 14:11
@PureWeen PureWeen closed this Nov 25, 2025
@github-actions github-actions bot locked and limited conversation to collaborators Dec 26, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

App hangs if PopModalAsync is called after PushModalAsync with single await Task.Yield()

2 participants