[Android] Keyboard: Fix inset handling for Window SoftInput modes#33902
[Android] Keyboard: Fix inset handling for Window SoftInput modes#33902NirmalKumarYuvaraj wants to merge 8 commits intodotnet:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses keyboard overlap and safe area handling issues on Android by refactoring how keyboard insets are managed for different WindowSoftInputModeAdjust modes (AdjustResize, AdjustPan, AdjustNothing). The fix centralizes keyboard inset handling in MauiWindowInsetListener by detecting the active SoftInputMode and applying appropriate padding to the CoordinatorLayout while managing child view padding to prevent double-padding issues.
Changes:
- Refactored
MauiWindowInsetListenerto handle keyboard insets based onSoftInputMode, applying bottom padding forAdjustResizeand consuming insets forAdjustPanto prevent layout conflicts - Removed redundant keyboard handling logic from
SafeAreaExtensions.csto centralize behavior inMauiWindowInsetListener - Added new helper method
GetAndroidSystemBarInsets()to test infrastructure for accurate system bar measurement in UI tests - Created comprehensive UI test pages and tests for both
AdjustResizeandAdjustPanmodes to validate keyboard behavior
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Core/src/Platform/Android/MauiWindowInsetListener.cs | Added keyboard inset handling logic based on SoftInputMode; handles CoordinatorLayout padding and child view padding reset/restoration for AdjustResize and AdjustPan modes |
| src/Core/src/Platform/Android/SafeAreaExtensions.cs | Removed redundant AdjustPan keyboard handling logic to consolidate in MauiWindowInsetListener |
| src/TestUtils/src/UITest.Appium/HelperExtensions.cs | Added GetAndroidSystemBarInsets() helper method and changed GetSystemBars() to internal visibility |
| src/Controls/tests/TestCases.HostApp/Issues/Issue32041.xaml | Created test page for AdjustResize mode with visual markers to verify keyboard behavior |
| src/Controls/tests/TestCases.HostApp/Issues/Issue32041.xaml.cs | Code-behind that sets SoftInput.AdjustResize mode for the test page |
| src/Controls/tests/TestCases.HostApp/Issues/Issue32041AdjustPan.xaml | Enhanced existing AdjustPan test page with additional AutomationIds for precise testing |
| src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32041.cs | UI test validating AdjustResize behavior measures element movement when keyboard shows/hides |
| src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32041AdjustPan.cs | Enhanced UI test for AdjustPan mode with improved assertions for layout and visibility |
|
/azp run maui-pr-uitests, maui-pr-devicetests |
|
Azure Pipelines successfully started running 2 pipeline(s). |
4fbcfec to
672f3b0
Compare
|
/rebase |
3b29a8a to
697d237
Compare
🤖 CI Test FeedbackWe ran the
The failing test hits a Suggestion: Add // Before
var rect = App.FindElement("BottomMarker").GetRect();
// After
App.WaitForElement("BottomMarker");
var rect = App.FindElement("BottomMarker").GetRect();This is a common Appium timing issue on emulators where layout changes from keyboard transitions may not be immediately reflected. |
|
/azp run maui-pr-uitests, maui-pr-devicetests |
|
Azure Pipelines successfully started running 2 pipeline(s). |
kubaflo
left a comment
There was a problem hiding this comment.
Could you please review the ai's summary?
🤖 AI Summary
📊 Review Session —
|
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🖥️ Issue32041 Issue32041 |
✅ FAIL — 609s | ❌ FAIL — 588s |
🖥️ Issue32041AdjustPan Issue32041AdjustPan |
||
🖥️ Issue32041FlyoutPage Issue32041FlyoutPage |
||
🖥️ Issue32041Shell Issue32041Shell |
||
🖥️ Issue32041TabbedPage Issue32041TabbedPage |
🔴 Without fix — 🖥️ Issue32041: FAIL ✅ · 609s
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:06:48.20
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
UITest.Core -> /home/vsts/work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
UITest.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
UITest.NUnit -> /home/vsts/work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
VisualTestUtils.MagickNet -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
UITest.Analyzers -> /home/vsts/work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
Controls.TestCases.Android.Tests -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
/home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.14] Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.50] Discovered: Controls.TestCases.Android.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
NUnit3TestExecutor discovered 5 of 5 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 04/25/2026 11:46:52 FixtureSetup for Issue32041(Android)
>>>>> 04/25/2026 11:46:55 VerifyContainerResizesWithAdjustResize Start
>>>>> 04/25/2026 11:47:16 VerifyContainerResizesWithAdjustResize Stop
>>>>> 04/25/2026 11:47:16 Log types: logcat, bugreport, server
Failed VerifyContainerResizesWithAdjustResize [21 s]
Error Message:
System.TimeoutException : Timed out waiting for element...
Stack Trace:
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
at Microsoft.Maui.TestCases.Tests.Issues.Issue32041.VerifyContainerResizesWithAdjustResize() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32041.cs:line 40
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
>>>>> 04/25/2026 11:47:20 FixtureSetup for Issue32041AdjustPan(Android)
>>>>> 04/25/2026 11:47:24 VerifyContainerDoesNotResizeWithAdjustPan Start
>>>>> 04/25/2026 11:47:30 VerifyContainerDoesNotResizeWithAdjustPan Stop
Passed VerifyContainerDoesNotResizeWithAdjustPan [5 s]
>>>>> 04/25/2026 11:47:31 FixtureSetup for Issue32041FlyoutPage(Android)
>>>>> 04/25/2026 11:47:36 FlyoutPageContainerResizesWithAdjustResize Start
>>>>> 04/25/2026 11:47:40 FlyoutPageContainerResizesWithAdjustResize Stop
>>>>> 04/25/2026 11:47:41 Log types: logcat, bugreport, server
Failed FlyoutPageContainerResizesWithAdjustResize [4 s]
Error Message:
FlyoutPage detail container should resize (height decrease) when keyboard appears with AdjustResize. Before: 1710px, After: 1710px
Assert.That(resizedHeight, Is.LessThan(initialHeight))
Expected: less than 1710
But was: 1710
Stack Trace:
at Microsoft.Maui.TestCases.Tests.Issues.Issue32041FlyoutPage.FlyoutPageContainerResizesWithAdjustResize() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32041FlyoutPage.cs:line 39
1) at Microsoft.Maui.TestCases.Tests.Issues.Issue32041FlyoutPage.FlyoutPageContainerResizesWithAdjustResize() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32041FlyoutPage.cs:line 39
>>>>> 04/25/2026 11:47:44 FixtureSetup for Issue32041Shell(Android)
>>>>> 04/25/2026 11:47:49 ShellContainerResizesWithAdjustResize Start
>>>>> 04/25/2026 11:47:53 ShellContainerResizesWithAdjustResize Stop
Passed ShellContainerResizesWithAdjustResize [4 s]
>>>>> 04/25/2026 11:47:56 FixtureSetup for Issue32041TabbedPage(Android)
>>>>> 04/25/2026 11:48:01 VerifyTabbedPageWithKeyboard Start
>>>>> 04/25/2026 11:48:20 VerifyTabbedPageWithKeyboard Stop
>>>>> 04/25/2026 11:48:20 Log types: logcat, bugreport, server
Failed VerifyTabbedPageWithKeyboard [19 s]
Error Message:
System.TimeoutException : Timed out waiting for element...
Stack Trace:
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
at Microsoft.Maui.TestCases.Tests.Issues.Issue32041TabbedPage.VerifyTabbedPageWithKeyboard() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32041TabbedPage.cs:line 35
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
NUnit Adapter 4.5.0.0: Test execution complete
Test Run Failed.
Total tests: 5
Passed: 2
Failed: 3
Total time: 1.7106 Minutes
🟢 With fix — 🖥️ Issue32041: FAIL ❌ · 588s
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:06:50.22
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Determining projects to restore...
All projects are up-to-date for restore.
Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13937179
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
UITest.Core -> /home/vsts/work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
UITest.NUnit -> /home/vsts/work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
VisualTestUtils.MagickNet -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
UITest.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
UITest.Analyzers -> /home/vsts/work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
Controls.TestCases.Android.Tests -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
/home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.11] Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.42] Discovered: Controls.TestCases.Android.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
NUnit3TestExecutor discovered 5 of 5 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 04/25/2026 11:56:58 FixtureSetup for Issue32041(Android)
>>>>> 04/25/2026 11:57:02 VerifyContainerResizesWithAdjustResize Start
>>>>> 04/25/2026 11:57:08 VerifyContainerResizesWithAdjustResize Stop
Passed VerifyContainerResizesWithAdjustResize [6 s]
>>>>> 04/25/2026 11:57:10 FixtureSetup for Issue32041AdjustPan(Android)
>>>>> 04/25/2026 11:57:14 VerifyContainerDoesNotResizeWithAdjustPan Start
>>>>> 04/25/2026 11:57:20 VerifyContainerDoesNotResizeWithAdjustPan Stop
Passed VerifyContainerDoesNotResizeWithAdjustPan [6 s]
>>>>> 04/25/2026 11:57:22 FixtureSetup for Issue32041FlyoutPage(Android)
>>>>> 04/25/2026 11:57:27 FlyoutPageContainerResizesWithAdjustResize Start
>>>>> 04/25/2026 11:57:31 FlyoutPageContainerResizesWithAdjustResize Stop
Passed FlyoutPageContainerResizesWithAdjustResize [4 s]
>>>>> 04/25/2026 11:57:34 FixtureSetup for Issue32041Shell(Android)
>>>>> 04/25/2026 11:57:39 ShellContainerResizesWithAdjustResize Start
>>>>> 04/25/2026 11:57:42 ShellContainerResizesWithAdjustResize Stop
Passed ShellContainerResizesWithAdjustResize [4 s]
>>>>> 04/25/2026 11:57:45 FixtureSetup for Issue32041TabbedPage(Android)
>>>>> 04/25/2026 11:57:50 VerifyTabbedPageWithKeyboard Start
>>>>> 04/25/2026 11:58:09 VerifyTabbedPageWithKeyboard Stop
>>>>> 04/25/2026 11:58:09 Log types: logcat, bugreport, server
Failed VerifyTabbedPageWithKeyboard [20 s]
Error Message:
System.TimeoutException : Timed out waiting for element...
Stack Trace:
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
at Microsoft.Maui.TestCases.Tests.Issues.Issue32041TabbedPage.VerifyTabbedPageWithKeyboard() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32041TabbedPage.cs:line 35
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
NUnit Adapter 4.5.0.0: Test execution complete
Test Run Failed.
Total tests: 5
Passed: 4
Failed: 1
Total time: 1.4018 Minutes
🔴 Without fix — 🖥️ Issue32041AdjustPan: ⚠️ ENV ERROR · 0s
Log file empty
🟢 With fix — 🖥️ Issue32041AdjustPan: ⚠️ ENV ERROR · 0s
Log file empty
🔴 Without fix — 🖥️ Issue32041FlyoutPage: ⚠️ ENV ERROR · 0s
Log file empty
🟢 With fix — 🖥️ Issue32041FlyoutPage: ⚠️ ENV ERROR · 0s
Log file empty
🔴 Without fix — 🖥️ Issue32041Shell: ⚠️ ENV ERROR · 0s
Log file empty
🟢 With fix — 🖥️ Issue32041Shell: ⚠️ ENV ERROR · 0s
Log file empty
🔴 Without fix — 🖥️ Issue32041TabbedPage: ⚠️ ENV ERROR · 0s
Log file empty
🟢 With fix — 🖥️ Issue32041TabbedPage: ⚠️ ENV ERROR · 0s
Log file empty
⚠️ Issues found
⚠️ Issue32041AdjustPan without fix:Exception calling "Matches" with "2" argument(s): "Value cannot be null. (Parameter 'input')"⚠️ Issue32041FlyoutPage without fix:Exception calling "Matches" with "2" argument(s): "Value cannot be null. (Parameter 'input')"⚠️ Issue32041Shell without fix:Exception calling "Matches" with "2" argument(s): "Value cannot be null. (Parameter 'input')"⚠️ Issue32041TabbedPage without fix:Exception calling "Matches" with "2" argument(s): "Value cannot be null. (Parameter 'input')"- ❌ Issue32041 FAILED with fix (should pass)
Device tests: 1 of 5 failed
⚠️ Issue32041AdjustPan with fix:Exception calling "Matches" with "2" argument(s): "Value cannot be null. (Parameter 'input')"⚠️ Issue32041FlyoutPage with fix:Exception calling "Matches" with "2" argument(s): "Value cannot be null. (Parameter 'input')"⚠️ Issue32041Shell with fix:Exception calling "Matches" with "2" argument(s): "Value cannot be null. (Parameter 'input')"⚠️ Issue32041TabbedPage with fix:Exception calling "Matches" with "2" argument(s): "Value cannot be null. (Parameter 'input')"
📁 Fix files reverted (2 files)
src/Core/src/Platform/Android/MauiWindowInsetListener.cssrc/Core/src/Platform/Android/SafeAreaExtensions.cs
🔍 Pre-Flight — Context & Validation
Issue: #32041 - net 10 rc2 keyboard overlap android
PR: #33902 - [Android] Keyboard: Fix inset handling for Window SoftInput modes
Platforms Affected: Android only
Files Changed: 2 implementation, 13 test
Key Findings
- Regression in .NET 10 RC2:
SoftInput.AdjustResizestopped resizing content, causing keyboard to overlap Entry fields at bottom of screen - Root cause: Previous inset handling didn't correctly apply keyboard padding to the CoordinatorLayout for AdjustResize mode
- Fix centralizes all keyboard inset logic in
MauiWindowInsetListener, removing fragmented handling fromSafeAreaExtensions.cs - Critical logic bug:
ApplyKeyboardInsetsreturn value is discarded —ApplyBottomNavViewInsetsruns unconditionally after and overwrites the keyboard padding for bottom-nav scenarios - Incomplete keyboard-dismiss path:
hasBottomNav == truebranch does nothing on dismiss (commented-out code) - Gate FAILED — tests did not behave as expected during CI verification
Code Review Summary
Verdict: NEEDS_CHANGES
Confidence: medium
Errors: 1 | Warnings: 3 | Suggestions: 2
Key code review findings:
- ❌
MauiWindowInsetListener.csline ~236-238:ApplyKeyboardInsetsreturn value discarded;ApplyBottomNavViewInsetsimmediately overwrites keyboard padding set for bottom-nav case ⚠️ MauiWindowInsetListener.cs~keyboard-dismiss branch:hasBottomNav == truepath does nothing on keyboard dismiss — contentView retains stale keyboard-height bottom padding⚠️ MauiWindowInsetListener.cs~AdjustPan branch: Consumes ALL insets (including system bars) while keyboard is visible — should only consume IME insets⚠️ Issue32041TabbedPage.cs: DuplicateAutomationIdvalues ("MainContainer", "TopLabel", "BottomMarker", "TestEntry") across both tabs- 💡 Hardcoded 200px movement thresholds are fragile on small Helix emulators
- 💡
VerifyContainerDoesNotResizeWithAdjustPantest name contradicts assertion body
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #33902 | Centralize keyboard insets in MauiWindowInsetListener; apply CoordinatorLayout bottom padding for AdjustResize; consume IME insets for AdjustPan | ❌ FAILED (Gate) | MauiWindowInsetListener.cs, SafeAreaExtensions.cs |
Has logic bug: return value discarded; bottom-nav dismiss path incomplete |
🔬 Code Review — Deep Analysis
Code Review — PR #33902
Independent Assessment
What this changes: Adds keyboard inset handling in MauiWindowInsetListener.ApplyKeyboardInsets for AdjustResize, AdjustPan, and AdjustNothing modes, adds a _wasKeyboardShowing guard to prevent double-application, removes keyboard handling from SafeAreaExtensions.cs (centralizing it), adds GetAndroidSystemBarInsets to HelperExtensions, and adds five new host-app pages + UI tests covering Issue 32041 across different navigation containers.
Inferred motivation: When SoftInput.AdjustResize is set, MAUI's existing inset pipeline was either double-applying padding or not resizing content correctly relative to the keyboard, causing the keyboard to overlap input fields.
Reconciliation with PR Narrative
Author claims: Refactors keyboard inset handling into MauiWindowInsetListener, removes redundant handling from SafeAreaExtensions.cs, adds comprehensive tests across content page, shell, tabbed page, flyout, and AdjustPan modes.
Agreement: The centralization approach is sound and follows the existing per-view registry pattern. The test coverage across navigation containers is thorough.
Disagreements / concerns: The ApplyKeyboardInsets return value is silently discarded (see ❌ below), and the AdjustPan inset-consuming behavior is overly aggressive. Several tests have assertions that may be fragile in CI.
Findings
❌ Error — ApplyKeyboardInsets return value is discarded; ApplyBottomNavViewInsets overwrites keyboard padding
MauiWindowInsetListener.cs, line 236–238:
ApplyKeyboardInsets(v, insets, bottomTabContainer, contentView, hasBottomNav, systemBars); // return ignored
ApplyBottomNavViewInsets(systemBars, displayCutout, hasBottomNav, contentView); // overwrites contentViewWhen AdjustResize + keyboard showing + hasBottomNav == true, ApplyKeyboardInsets sets contentView.SetPadding(..., bottomInset) where bottomInset = Math.Max(systemBars.Bottom, imeInsets.Bottom) (roughly the keyboard height). Then ApplyBottomNavViewInsets immediately runs and sets contentView.SetPadding(0, 0, 0, Math.Max(systemBars.Bottom, displayCutout.Bottom)) — just the nav-bar height — overwriting the keyboard padding.
If correctness in the Shell+bottom-tabs case (Issue32041Shell) depends on that padding being preserved through this pipeline, it won't be. The discarded WindowInsetsCompat.Consumed result is also silent — callers of OnApplyWindowInsets see the return from ApplyDefaultWindowInsets, not from ApplyKeyboardInsets. Consider: (a) checking the return value and short-circuiting, or (b) restructuring so ApplyBottomNavViewInsets is skipped when ApplyKeyboardInsets consumed the insets.
⚠️ Warning — Commented-out code leaves bottom-tabs + keyboard-dismiss path incomplete
MauiWindowInsetListener.cs, inside the AdjustResize keyboard-dismiss branch:
else if (!isKeyboardShowing && _wasKeyboardShowing && !IsImeAnimating)
{
_wasKeyboardShowing = false;
if (hasBottomNav)
{
//RequestInsetsForDescendants(contentView); // ← dead code, no explanation
}
else
{
coordinatorLayout.SetPadding(0, 0, 0, 0);
coordinatorLayout.Post(() => RequestInsetsForDescendants(coordinatorLayout));
}
}For the hasBottomNav == true path, keyboard dismissal does nothing beyond resetting the flag. The non-bottom-nav path explicitly zeros padding and re-requests insets. The commented line is unexplained. If contentView's stale bottom padding is not restored after keyboard dismissal, it will cause a visual layout issue.
⚠️ Warning — AdjustPan consumes ALL insets (not just IME) while keyboard is visible
MauiWindowInsetListener.cs, line ~412–416:
else if (adjustMode == SoftInput.AdjustPan)
{
if (isKeyboardShowing && !IsImeAnimating)
{
return WindowInsetsCompat.Consumed;
}
}This blanket-consumes all inset types (system bars, display cutout, IME) while the keyboard is visible in AdjustPan mode. Status-bar and notch safe-area insets would be suppressed from reaching child views, potentially causing the status bar to overlap content on the top edge while the keyboard is visible. Should only consume the IME inset, not system bars.
⚠️ Warning — Duplicate AutomationId values across tabs in Issue32041TabbedPage
Issue32041TabbedPage.cs — CreateContentPage is called twice and both pages receive identical AutomationId values: "MainContainer", "TopLabel", "BottomMarker", "TestEntry". Appium element lookups by AutomationId are not guaranteed to return the active tab's element when duplicates exist.
💡 Suggestion — Hardcoded 200px thresholds are fragile
Issue32041.cs, Issue32041Shell.cs, Issue32041FlyoutPage.cs tests assert upwardMovement/heightReduction > 200. On smaller Helix emulators, the software keyboard may be shorter than 200px. Consider proportional threshold or deriving from actual IME inset height.
💡 Suggestion — VerifyContainerDoesNotResizeWithAdjustPan name contradicts test body
Issue32041AdjustPan.cs: Test name says "DoesNotResize" but body asserts afterBottom < initialBottom (bottom marker moves up). Name should be updated to match actual tested behavior.
CI Status
Blast Radius
- All Android apps using
SoftInput.AdjustResize— directly impacted; this changes the bottom padding logic for the entire CoordinatorLayout when keyboard appears. - All Android apps using
SoftInput.AdjustPan—SafeAreaExtensions.csAdjustPan handling removed; keyboard inset is now consumed at a different point. - Apps with Shell bottom tabs — may be affected by the execution-order bug where
ApplyBottomNavViewInsetsoverwrites keyboard padding. - No iOS/Windows impact — changes are pure Android platform code.
Failure-Mode Probes
- AdjustResize + Shell bottom tabs:
ApplyKeyboardInsetssetscontentViewpadding to keyboard height, thenApplyBottomNavViewInsetsoverwrites it with nav-bar height only → keyboard still overlaps content in Shell scenarios. - AdjustResize + no bottom nav:
coordinatorLayout.SetPadding(0,0,0, bottomInset)— then on dismiss, resets to (0,0,0,0) and re-requests insets — this path looks correct. - AdjustPan + keyboard visible: IME insets AND system bar insets consumed → status bar area may show behind content edge.
- Keyboard dismiss with bottom nav: Does nothing (commented-out code) → contentView retains stale keyboard-height bottom padding → layout visually broken until next inset cycle.
Verdict: NEEDS_CHANGES
Confidence: medium
Key issues:
- ❌
ApplyKeyboardInsetsreturn value discarded —ApplyBottomNavViewInsetsoverwrites keyboard padding. ⚠️ Commented-out keyboard-dismiss path for bottom-nav leaves layout in broken state.⚠️ AdjustPanover-consumes insets (system bars too, not just IME).- CI is currently failing.
🔧 Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix (claude-opus-4.6) | Keyboard-Aware Bottom Nav Padding (Single Point of Truth) — integrate keyboard awareness into existing bottom-nav padding logic; contentView padding = max(navBarHeight, keyboardHeight) when AdjustResize+keyboard visible; no separate ApplyKeyboardInsets method | ✅ PASS | 1 file (MauiWindowInsetListener.cs) | No separate method; single decision point |
| 2 | try-fix (claude-sonnet-4.6) | IME-Aware contentView as Single Padding Authority — contentView padding = isKeyboardShowing ? max(systemBottom, imeBottom) : systemBottom; no explicit dismiss-path needed since system calls OnApplyWindowInsets on every IME state change |
✅ PASS | 1 file (MauiWindowInsetListener.cs) | Minimal change; most elegant; relies on Android inset dispatch naturally |
| 3 | try-fix (gpt-5.3-codex) | Insets Handoff with IME-Only Consumption — kept decomposed methods but fixed ordering (bottom-nav first, then keyboard can override); IME-only consumption for AdjustPan (not all insets) | ✅ PASS | 1 file (MauiWindowInsetListener.cs) | Closest to PR structure but with ordering fixed |
| 4 | try-fix (gpt-5.4) | Dispatch-time IME normalization in OnApplyWindowInsets | ❌ FAIL | 1 file | Inset rewriting insufficient; geometry assertions failed |
| PR | PR #33902 | Centralize keyboard insets in MauiWindowInsetListener; separate ApplyKeyboardInsets method; remove AdjustPan handling from SafeAreaExtensions | ❌ FAILED (Gate) | 2 files | ApplyKeyboardInsets return value discarded; ApplyBottomNavViewInsets overwrites keyboard padding |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| claude-opus-4.6 | 2 | Yes | Animation-Callback-Only: move keyboard padding into WindowInsetsAnimationCompat.Callback OnStart/OnProgress/OnEnd for smooth animated resize |
| claude-sonnet-4.6 | 2 | Yes | Spacer-view: append invisible spacer view as last child whose height = max(navBarHeight, keyboardHeight), eliminating all SetPadding conflicts |
| gpt-5.3-codex | 2 | Yes | Insets state machine: Hidden→Showing→Visible→Hiding with monotonic IME updates and bottom margin instead of padding |
| gpt-5.4 | 2 | Yes | Mode-switch: use WindowCompat.SetDecorFitsSystemWindows(window, true) for AdjustResize to use native Android resize |
Cross-pollination ideas are more complex; given 3 passing candidates already, additional exploration not warranted.
Exhausted: Yes (all 4 models queried, cross-pollination round completed)
Selected Fix: Candidate #2 (claude-sonnet-4.6) — IME-Aware contentView as Single Padding Authority
Reason: Most minimal change (60 lines, 1 file), relies on Android's natural inset dispatch to handle dismiss path without explicit state management, single expression eliminates the padding overwrite race condition entirely. Candidate #1 also passes but is larger; Candidate #3 keeps the decomposed-method structure closest to PR but requires careful ordering. Candidate #2 is the simplest correct solution.
📋 Report — Final Recommendation
⚠️ Final Recommendation: REQUEST CHANGES
Phase Status
| Phase | Status | Notes |
|---|---|---|
| Pre-Flight | ✅ COMPLETE | Issue #32041 — Android AdjustResize keyboard overlap regression in .NET 10 RC2 |
| Code Review | NEEDS_CHANGES (medium) | 1 error, 3 warnings |
| Gate | ❌ FAILED | Android — tests did not behave as expected |
| Try-Fix | ✅ COMPLETE | 4 attempts, 3 passing (Candidates #1, #2, #3) |
| Report | ✅ COMPLETE |
Code Review Impact on Try-Fix
The code-review ❌ Error (discarded ApplyKeyboardInsets return value; ApplyBottomNavViewInsets overwrites keyboard padding) was the central finding that guided all three successful fix attempts. Each model independently identified the "two writers for contentView.PaddingBottom" race condition as the root problem and resolved it via different architectural approaches:
- Candidate [Draft] Readme WIP #1 eliminated the separate
ApplyKeyboardInsetsmethod entirely (single inline computation) - Candidate Update README.md #2 used a single IME-aware expression for contentView padding in the existing bottom-nav path
- Candidate Third #3 fixed execution ordering between the two methods
The
Summary
PR #33902 fixes a real regression in .NET 10 RC2 where SoftInput.AdjustResize stopped resizing content above the keyboard on Android. The centralization approach (moving keyboard inset logic to MauiWindowInsetListener, removing fragmented handling from SafeAreaExtensions) is architecturally sound. However, the implementation has a correctness bug: ApplyKeyboardInsets is called but its return value is discarded, and ApplyBottomNavViewInsets unconditionally runs afterward, overwriting the keyboard padding in the bottom-nav case. Additionally, the keyboard-dismiss path for hasBottomNav==true does nothing (commented-out code), leaving stale padding after keyboard dismissal.
Gate failed, and Try-Fix found 3 simpler alternative fixes that pass the test. The recommended fix is Candidate #2 — the minimal IME-aware single-expression approach that eliminates the padding race without adding new state tracking.
Root Cause
ApplyDefaultWindowInsets calls ApplyKeyboardInsets (which correctly sets contentView padding to keyboard height) then immediately calls ApplyBottomNavViewInsets (which unconditionally sets contentView padding to nav-bar height only), overwriting the keyboard padding. The return value of ApplyKeyboardInsets (which returns WindowInsetsCompat.Consumed when handled) is discarded, so the bottom-nav path has no knowledge of whether keyboard handling already occurred.
Fix Quality
The PR's fix approach direction is correct — centralizing keyboard inset handling in MauiWindowInsetListener is the right architectural move. However, the execution has multiple issues:
- Critical: Discarded return value +
ApplyBottomNavViewInsetsoverwriting keyboard padding in the bottom-nav case - Medium: Incomplete keyboard-dismiss path for
hasBottomNav==true(commented-out restoration) - Low:
AdjustPanbranch consumes all insets instead of only IME insets - Test quality: Duplicate
AutomationIdvalues across TabbedPage tabs; hardcoded 200px thresholds
Recommended fix (Candidate #2): Replace the separate ApplyKeyboardInsets method with a single IME-aware expression in the existing bottom-nav padding block:
var systemBottomInset = Math.Max(systemBars?.Bottom ?? 0, displayCutout?.Bottom ?? 0);
var bottomInset = isKeyboardShowing
? Math.Max(systemBottomInset, imeInsets?.Bottom ?? 0)
: systemBottomInset;
contentView?.SetPadding(0, 0, 0, bottomInset);This eliminates the two-writer race, requires ~60 lines in 1 file (vs. 150+ lines in 2 files for the PR), and relies on Android's natural inset dispatch to call OnApplyWindowInsets when IME state changes, avoiding the need for an explicit dismiss-path.
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
This pull request addresses issues with keyboard overlap and safe area handling on Android when using different
SoftInputmodes (AdjustResizeandAdjustPan). It introduces new test cases, improves platform-specific logic for keyboard and safe area insets, and enhances the UI test infrastructure for more accurate validation of layout changes when the keyboard appears or disappears.The most important changes are:
Android Keyboard and Safe Area Handling Improvements:
MauiWindowInsetListenerto properly handle keyboard insets forAdjustResizeandAdjustPanmodes. This includes applying or resetting bottom padding on theCoordinatorLayoutand its descendants based on the keyboard state and soft input mode, ensuring no double padding and correct layout restoration when the keyboard is shown or hidden. [1] [2] [3]SafeAreaExtensions.csto centralize logic inMauiWindowInsetListener, preventing conflicts and ensuring consistent behavior.Test Cases and Validation:
Issue32041.xamland code-behind) to verify that the keyboard does not overlap input fields whenSoftInput.AdjustResizeis set, and that the layout resizes appropriately. [1] [2]Issue32041.cs) that measures and asserts the movement of UI elements when the keyboard appears/disappears, ensuring the fix works as intended.AdjustPantest page and test (Issue32041AdjustPan.xaml,Issue32041AdjustPan.cs) with more precise automation IDs and improved assertions for layout and element visibility during keyboard transitions. [1] [2] [3] [4]Test Infrastructure Enhancements:
GetAndroidSystemBarInsetstoUITest.Appium.HelperExtensionsfor accurate retrieval of status and navigation bar heights in Android UI tests, allowing for precise layout assertions.GetSystemBarsfor internal use.Dependency Updates:
usingdirective forAndroidX.CoordinatorLayout.Widgetto support new logic.These changes collectively ensure that the app's content is correctly resized or panned in response to the keyboard on Android, and that UI tests can reliably validate this behavior.
Issues Fixed
Fixes #32041
AdjustNothing.mov
AdjustNothing.mov
AdjustResize.mov
AdjustResize.mov
AdjustPan.mov
AdjustPan.mov
API.30.mov
API.36.mov