Skip to content

Commit

Permalink
Fix null reference exception in KeyboardAutoManagerScroll when UIWind…
Browse files Browse the repository at this point in the history
…ow is null (#21753)

* Fix null reference when window is null

When using certain controls ie bottom sheets and search bars there can be a crash when the keyboard displays. Check for null & return early if it is.

* set flag to false if returning

* remove change on line 1

* Add IsDescendant of ContainerVC

* remove the extra IsKeyboardAutoScrollHandling flag

* remove extra style changes

* Add UITest

* Use UIView AccessibilityIdentifier on UITest

* Add ignore in platform and remove catch in favor of rebasing main

---------

Co-authored-by: tj-devel709 <[email protected]>
  • Loading branch information
Axemasta and tj-devel709 authored Apr 26, 2024
1 parent 63eb6b6 commit 7a37ebf
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue21726"
Title="Issue21726">
<VerticalStackLayout>
<Button Text="AddVC" AutomationId="AddVC" Clicked="AddVC"/>
</VerticalStackLayout>
</ContentPage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.Linq;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Xaml;
using System.Threading.Tasks;

namespace Maui.Controls.Sample.Issues;

[XamlCompilation(XamlCompilationOptions.Compile)]
[Issue(IssueTracker.Github, 21726, "Modal with a bottom sheet should not crash iOS Keyboard Scroll", PlatformAffected.iOS)]
public partial class Issue21726 : ContentPage
{
public Issue21726()
{
InitializeComponent();
}

void AddVC (object sender, EventArgs e)
{
#if IOS
var window = UIKit.UIApplication.SharedApplication
.ConnectedScenes
.OfType<UIKit.UIWindowScene>()
.SelectMany(s => s.Windows)
.FirstOrDefault(w => w.IsKeyWindow);

var rootVC = window?.RootViewController;
while (rootVC?.PresentedViewController != null)
{
rootVC = rootVC.PresentedViewController;
}

if (rootVC is not null) {
var testVC = new TestViewController();

var testNC = new UIKit.UINavigationController(testVC)
{
ModalPresentationStyle = UIKit.UIModalPresentationStyle.FullScreen
};

rootVC.PresentViewController(testNC, true, null);
}
#endif
}

#if IOS
public class TestViewController: UIKit.UIViewController {

UIKit.UITextField TextField1;
UIKit.UIButton Button1;

public override void ViewDidLoad() {
base.ViewDidLoad();

View.BackgroundColor = UIKit.UIColor.White;

TextField1 = new UIKit.UITextField(new CoreGraphics.CGRect(20, 120, 200, 20))
{
Placeholder = "TextField1",
BorderStyle = UIKit.UITextBorderStyle.RoundedRect,
AccessibilityIdentifier = "TextField1"
};

Button1 = new UIKit.UIButton(new CoreGraphics.CGRect(20, 320, 200, 40));
Button1.SetTitle("Dismiss", UIKit.UIControlState.Normal);
Button1.BackgroundColor = UIKit.UIColor.SystemBlue;
Button1.AccessibilityIdentifier = "Button1";
Button1.TouchUpInside += (sender, e) => {
DismissViewController(true, null);
};

View.AddSubview(TextField1);
View.AddSubview(Button1);
}
}
#endif
}
28 changes: 28 additions & 0 deletions src/Controls/tests/UITests/Tests/Issues/Issue21726.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.AppiumTests.Issues
{
public class Issue21726 : _IssuesUITest
{
public Issue21726(TestDevice device) : base(device)
{
}

public override string Issue => "Modal with a bottom sheet should not crash iOS Keyboard Scroll";

[Test]
public void PushViewControllerWithNullWindow()
{
this.IgnoreIfPlatforms([TestDevice.Android, TestDevice.Mac, TestDevice.Windows]);

App.WaitForElement("AddVC");
App.Click("AddVC");
App.WaitForElement("TextField1").Click();
App.WaitForElement("Button1").Click();
var mainPageElement = App.WaitForElement("AddVC");
Assert.NotNull(mainPageElement);
}
}
}
9 changes: 8 additions & 1 deletion src/Core/src/Platform/iOS/KeyboardAutoManagerScroll.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,8 @@ internal static async Task AdjustPositionDebounce()
internal static void AdjustPosition()
{
if (ContainerView is null
|| (View is not UITextField && View is not UITextView))
|| (View is not UITextField && View is not UITextView)
|| !View.IsDescendantOfView(ContainerView))
{
IsKeyboardAutoScrollHandling = false;
return;
Expand All @@ -311,6 +312,12 @@ internal static void AdjustPosition()
var rootViewOrigin = new CGPoint(ContainerView.Frame.GetMinX(), ContainerView.Frame.GetMinY());
var window = ContainerView.Window;

if (window is null)
{
IsKeyboardAutoScrollHandling = false;
return;
}

var intersectRect = CGRect.Intersect(KeyboardFrame, window.Frame);
var kbSize = intersectRect == CGRect.Empty ? new CGSize(KeyboardFrame.Width, 0) : intersectRect.Size;

Expand Down

0 comments on commit 7a37ebf

Please sign in to comment.