Fix content page title clipping on Android API < 30 with window insets compatibility#32537
Fix content page title clipping on Android API < 30 with window insets compatibility#32537
Conversation
4d98c30 to
d95b336
Compare
|
@copilot can you update the description based on your changes? The initial changes you made were wrong |
Updated PR description to reflect the actual fix. The solution addresses API 28-29 compatibility in MauiWindowInsetListener.cs by using legacy SystemWindowInsets for older Android versions, rather than modifying ContentPage behavior. Commit: d95b336 |
284e2e9 to
6380231
Compare
There was a problem hiding this comment.
Pull Request Overview
This PR fixes Shell content page title clipping on Android API 28-29 by adding API level fallback logic for window insets retrieval. The issue occurred because WindowInsetsCompat.Type.SystemBars() and WindowInsetsCompat.Type.DisplayCutout() APIs were introduced in API 30, causing incorrect toolbar positioning on older devices.
Key changes:
- Added API level detection in
MauiWindowInsetListener.csto use deprecatedSystemWindowInsetsfor API 28-29 - Implemented Google's workaround for API 28-29 inset dispatch bug with recursive child propagation
- Added
NavigationAreaInsetListenerinShellItemRendererfor API 28-29 bottom navigation handling - Created UI test (Issue32278) to verify content positioning across navigation
Reviewed Changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Core/src/Platform/Android/MauiWindowInsetListener.cs | Added API 28-29 fallback logic for window insets retrieval using deprecated SystemWindowInsets property and recursive inset dispatch workaround |
| src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellPageContainer.cs | Added BoopContainer debug class and OnApplyWindowInsets override (appears to be temporary debug code) |
| src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellContentFragment.cs | Changed to use BoopContainer instead of ShellPageContainer (likely debug code) |
| src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellItemRenderer.cs | Added NavigationAreaInsetListener for API 28-29 to dispatch insets to navigation area children |
| src/Controls/tests/TestCases.HostApp/Issues/Issue32278.xaml.cs | Added UI test page with Shell navigation to verify content positioning |
| src/Controls/tests/TestCases.HostApp/Issues/Issue32278.xaml | XAML definition for Issue32278 Shell test |
| src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32278.cs | NUnit test implementation to verify toolbar doesn't clip content |
| .vscode/settings.json | Changed default solution from .slnx to .slnf (unrelated local config change) |
| .github/instructions/common-testing-patterns.md | Added Android emulator startup documentation |
| public override WindowInsets OnApplyWindowInsets(WindowInsets insets) | ||
| { | ||
| return base.OnApplyWindowInsets(insets); | ||
| } |
There was a problem hiding this comment.
The OnApplyWindowInsets override in the base ShellPageContainer class only calls the base implementation without adding any functionality. This appears to be debug/development code.
Recommendation: Remove this override unless there's a specific reason it's needed. If it's for debugging purposes, it should be removed before merging. Empty overrides that just call base add no value and create maintenance burden.
| public override WindowInsets OnApplyWindowInsets(WindowInsets insets) | |
| { | |
| return base.OnApplyWindowInsets(insets); | |
| } |
.vscode/settings.json
Outdated
| @@ -1,3 +1,3 @@ | |||
| { | |||
| "dotnet.defaultSolution": "Microsoft.Maui-vscode.slnx" | |||
| "dotnet.defaultSolution": "Microsoft.Maui-vscode.slnf" | |||
There was a problem hiding this comment.
The VS Code settings change from .slnx to .slnf appears to be an unintended local configuration change that should not be committed.
Issue: This changes the default solution file for all developers, which is unrelated to fixing the Shell title clipping issue.
Recommendation: Revert this change. Personal IDE settings should not be committed unless they're intentional improvements documented in the PR.
| "dotnet.defaultSolution": "Microsoft.Maui-vscode.slnf" | |
| "dotnet.defaultSolution": "Microsoft.Maui.slnx" |
| var returnValue = ApplyDefaultWindowInsets(v, insets); | ||
|
|
||
| // For API < 30 and CoordinatorLayout only, apply Google's workaround to dispatch to all children | ||
| if ((int)global::Android.OS.Build.VERSION.SdkInt < 30 && v is CoordinatorLayout coordinatorLayout) |
There was a problem hiding this comment.
Using (int)global::Android.OS.Build.VERSION.SdkInt < 30 for API level checking is inconsistent with the approach used elsewhere in this method.
Issue: Line 277 uses OperatingSystem.IsAndroidVersionAtLeast(30) while line 214 uses (int)global::Android.OS.Build.VERSION.SdkInt < 30. These should use the same approach for consistency.
Recommendation: Use !OperatingSystem.IsAndroidVersionAtLeast(30) for consistency:
if (!OperatingSystem.IsAndroidVersionAtLeast(30) && v is CoordinatorLayout coordinatorLayout)This matches the pattern used in line 277 and improves code consistency.
| if ((int)global::Android.OS.Build.VERSION.SdkInt < 30 && v is CoordinatorLayout coordinatorLayout) | |
| if (!OperatingSystem.IsAndroidVersionAtLeast(30) && v is CoordinatorLayout coordinatorLayout) |
| void SetupNavigationAreaInsetListener() | ||
| { | ||
| // Only set up listener for API 28-29 | ||
| if ((int)global::Android.OS.Build.VERSION.SdkInt >= 30) |
There was a problem hiding this comment.
Using (int)global::Android.OS.Build.VERSION.SdkInt >= 30 for API level checking is inconsistent with the approach used in MauiWindowInsetListener.cs.
Issue: The main fix in MauiWindowInsetListener.cs (line 277) uses OperatingSystem.IsAndroidVersionAtLeast(30) for API level detection, but this code uses a different pattern.
Recommendation: Use OperatingSystem.IsAndroidVersionAtLeast(30) for consistency:
if (OperatingSystem.IsAndroidVersionAtLeast(30))
return;This improves consistency across the codebase and follows the same pattern established in the core fix.
| if ((int)global::Android.OS.Build.VERSION.SdkInt >= 30) | |
| if (OperatingSystem.IsAndroidVersionAtLeast(30)) |
src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellContentFragment.cs
Outdated
Show resolved
Hide resolved
ee47698 to
744f41c
Compare
e53c414 to
5d7a751
Compare
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
|
@PureWeen Is this just for shell? Im seeing the same issue on android 9 using NavigationPage not shell, with the nav bar hidden - |
no it's for navigationpage and shell I need to fix the title did you test the nugets? |
|
@copilot can you update the description and title of this PR to better reflect the changes? |
Updated PR title and description to accurately reflect that the fix addresses window insets issues for both NavigationPage and Shell on Android API 28-29, not just Shell-specific title clipping. The fix implements Google's workaround for the API 28-29 inset dispatch bug that affects both navigation modes when system UI elements (status bar, navigation bar) clip page content. |
|
thanks @PureWeen, will give it a test tomorrow |
|
@copilot this pr fixes all apis lower than 30 Please update title and description |
Updated the PR title to "Fix content page title clipping on Android API < 30 with window insets compatibility" and revised the description to clearly indicate the fix applies to all Android versions below API 30 (including API 28 and API 29). |
|
|
@PureWeen just tested the PR and all looks good, thanks |
amazing! Thank you for testing |


Fix Window Insets on Android API < 30 (NavigationPage and Shell)
Description
This PR addresses window insets issues on Android versions below API 30 (Android 11) affecting both Shell and NavigationPage navigation. The fix implements Google's workaround for the inset dispatch bug present in Android API 28 and API 29.
Changes Made
1. NavigationRootManager.cs
Added
ViewGroupCompat.InstallCompatInsetsDispatch()for API < 30 to ensure window insets are properly dispatched to all children recursively. This implements Google's workaround for the inset dispatch bug where one child consuming insets blocks all siblings from receiving them.Issue: On Android API < 30, when one view consumes window insets, sibling views don't receive them, causing content to be clipped by system UI (status bar, navigation bar, etc.). This affects both Shell navigation and NavigationPage with hidden navigation bars.
Defensive Programming: Added null check and logging for
_rootViewto help with future debugging and prevent potential null reference exceptions. Uses_mauiContext?.CreateLogger<NavigationRootManager>()?.LogWarning()with the properMicrosoft.Extensions.Loggingusing directive for logging integration.2. Test Case (Issue32526)
Navigation.PushAsync()Affected Android Versions
Affected Scenarios
Issues Fixed
Fixes #32526
💡 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.