diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue21109.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue21109.cs
new file mode 100644
index 000000000000..0b34217faab8
--- /dev/null
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue21109.cs
@@ -0,0 +1,33 @@
+#if ANDROID
+using NUnit.Framework;
+using NUnit.Framework.Legacy;
+using UITest.Appium;
+using UITest.Core;
+
+namespace Microsoft.Maui.TestCases.Tests.Issues
+{
+ public class Issue21109 : _IssuesUITest
+ {
+ public Issue21109(TestDevice device) : base(device) { }
+
+ public override string Issue => "[Android] MAUI 8.0.3 -> 8.0.6 regression: custom handler with key listener no longer works";
+
+ [Test]
+ [Category(UITestCategories.Entry)]
+ public void EntryReturnTypeWorks()
+ {
+ App.WaitForElement("WaitForStubControl");
+
+ // Verify that ReturnType works as expected.
+ if (App.IsKeyboardShown())
+ App.DismissKeyboard();
+
+ var returnType1 = App.FindElement("ReturnTypeResult").GetText();
+ App.Tap("ReturnTypeEntry");
+ App.EnterText("ReturnTypeEntry", "a");
+ var returnType2 = App.FindElement("ReturnTypeResult").GetText();
+ ClassicAssert.AreNotEqual(returnType1, returnType2);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases/Issues/Issue21109.xaml b/src/Controls/tests/TestCases/Issues/Issue21109.xaml
new file mode 100644
index 000000000000..4fb100db6541
--- /dev/null
+++ b/src/Controls/tests/TestCases/Issues/Issue21109.xaml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases/Issues/Issue21109.xaml.cs b/src/Controls/tests/TestCases/Issues/Issue21109.xaml.cs
new file mode 100644
index 000000000000..a4e871b0bf3b
--- /dev/null
+++ b/src/Controls/tests/TestCases/Issues/Issue21109.xaml.cs
@@ -0,0 +1,65 @@
+using System;
+using Microsoft.Maui;
+using Microsoft.Maui.Controls;
+using Microsoft.Maui.Controls.Xaml;
+using Microsoft.Maui.Hosting;
+
+namespace Maui.Controls.Sample.Issues
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ [Issue(IssueTracker.Github, 21109, "[Android] MAUI 8.0.3 -> 8.0.6 regression: custom handler with key listener no longer works", PlatformAffected.All)]
+ public partial class Issue21109 : ContentPage
+ {
+ public Issue21109()
+ {
+ InitializeComponent();
+
+ ReturnTypeResult.Text = $"ReturnType: {ReturnTypeEntry.ReturnType}";
+ }
+
+ void OnReturnTypeEntryTextChanged(object sender, TextChangedEventArgs e)
+ {
+ Random rnd = new Random();
+ var returnTypeCount = Enum.GetNames(typeof(ReturnType)).Length;
+
+ ReturnType returnType = ReturnType.Default;
+
+ do
+ {
+ returnType = (ReturnType)rnd.Next(0, returnTypeCount);
+ } while (returnType == ReturnTypeEntry.ReturnType);
+
+ ReturnTypeEntry.ReturnType = returnType;
+ ReturnTypeResult.Text = $"ReturnType: {returnType}";
+ }
+ }
+
+ public class Issue21109DecimalEntry : Entry
+ {
+ public Issue21109DecimalEntry()
+ {
+ Keyboard = Keyboard.Numeric;
+ }
+ }
+
+ public static class Issue21109Extensions
+ {
+ public static MauiAppBuilder Issue21109AddMappers(this MauiAppBuilder builder)
+ {
+ builder.ConfigureMauiHandlers(handlers =>
+ {
+ Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping(nameof(Issue21109DecimalEntry), (handler, view) =>
+ {
+ if (view is Issue21109DecimalEntry)
+ {
+#if ANDROID
+ handler.PlatformView.KeyListener = new Platform.Issue21109NumericKeyListener(handler.PlatformView.InputType);
+#endif
+ }
+ });
+ });
+
+ return builder;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases/MauiProgram.cs b/src/Controls/tests/TestCases/MauiProgram.cs
index 35d9a40575be..9f9ce1d3297a 100644
--- a/src/Controls/tests/TestCases/MauiProgram.cs
+++ b/src/Controls/tests/TestCases/MauiProgram.cs
@@ -1,4 +1,5 @@
using System;
+using Maui.Controls.Sample.Issues;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Hosting;
@@ -8,18 +9,22 @@ namespace Maui.Controls.Sample
{
public static class MauiProgram
{
- public static MauiApp CreateMauiApp() =>
- MauiApp
- .CreateBuilder()
- #if IOS || ANDROID
- .UseMauiMaps()
- #endif
- .UseMauiApp()
+ public static MauiApp CreateMauiApp()
+ {
+ var appBuilder = MauiApp.CreateBuilder();
+
+#if IOS || ANDROID
+ appBuilder.UseMauiMaps();
+#endif
+ appBuilder.UseMauiApp()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
})
- .Build();
+ .Issue21109AddMappers();
+
+ return appBuilder.Build();
+ }
}
class App : Application
diff --git a/src/Controls/tests/TestCases/Platforms/Android/Issue21109NumericKeyListener.cs b/src/Controls/tests/TestCases/Platforms/Android/Issue21109NumericKeyListener.cs
new file mode 100644
index 000000000000..9ce1099c40bf
--- /dev/null
+++ b/src/Controls/tests/TestCases/Platforms/Android/Issue21109NumericKeyListener.cs
@@ -0,0 +1,25 @@
+using Android.Text;
+using Android.Text.Method;
+using Android.Views;
+using Microsoft.Maui.Controls;
+using AView = Android.Views.View;
+
+namespace Maui.Controls.Sample.Platform;
+
+public class Issue21109NumericKeyListener : NumberKeyListener
+{
+ public override InputTypes InputType { get; }
+
+ protected override char[] GetAcceptedChars() => "0123456789-,.".ToCharArray();
+
+ public Issue21109NumericKeyListener(InputTypes inputType)
+ {
+ InputType = inputType;
+ }
+
+ public override bool OnKeyDown(AView view, IEditable content, Keycode keyCode, KeyEvent e)
+ {
+ Application.Current.MainPage.DisplayAlert("OnKeyDown", string.Empty, "Ok");
+ return base.OnKeyDown(view, content, keyCode, e);
+ }
+}
\ No newline at end of file
diff --git a/src/Core/src/Handlers/Entry/EntryHandler.Android.cs b/src/Core/src/Handlers/Entry/EntryHandler.Android.cs
index 636f4d2532a4..587cee125e9d 100644
--- a/src/Core/src/Handlers/Entry/EntryHandler.Android.cs
+++ b/src/Core/src/Handlers/Entry/EntryHandler.Android.cs
@@ -42,7 +42,6 @@ public override void SetVirtualView(IView view)
// TODO: NET8 issoto - Change the return type to MauiAppCompatEditText
protected override void ConnectHandler(AppCompatEditText platformView)
{
- platformView.ViewAttachedToWindow += OnViewAttachedToWindow;
platformView.TextChanged += OnTextChanged;
platformView.FocusChange += OnFocusedChange;
platformView.Touch += OnTouch;
@@ -54,7 +53,6 @@ protected override void DisconnectHandler(AppCompatEditText platformView)
{
_clearButtonDrawable = null;
- platformView.ViewAttachedToWindow -= OnViewAttachedToWindow;
platformView.TextChanged -= OnTextChanged;
platformView.FocusChange -= OnFocusedChange;
platformView.Touch -= OnTouch;
@@ -148,14 +146,6 @@ static void MapFocus(IEntryHandler handler, IEntry entry, object? args)
handler.PlatformView.Focus(request);
}
- void OnViewAttachedToWindow(object? sender, ViewAttachedToWindowEventArgs e)
- {
- if (PlatformView is null || VirtualView is null)
- return;
-
- PlatformView.UpdateReturnType(VirtualView);
- }
-
void OnTextChanged(object? sender, TextChangedEventArgs e)
{
if (VirtualView == null)
diff --git a/src/Core/src/Platform/Android/EditTextExtensions.cs b/src/Core/src/Platform/Android/EditTextExtensions.cs
index c344b60d1081..ded06100cd6b 100644
--- a/src/Core/src/Platform/Android/EditTextExtensions.cs
+++ b/src/Core/src/Platform/Android/EditTextExtensions.cs
@@ -1,5 +1,5 @@
using System;
-using System.Collections.Generic;
+using Android.Content;
using Android.Content.Res;
using Android.Graphics.Drawables;
using Android.Text;
@@ -203,6 +203,10 @@ public static void UpdateReturnType(this EditText editText, IEntry entry)
{
editText.SetInputType(entry);
editText.ImeOptions = entry.ReturnType.ToPlatform();
+
+ // Restart the input on the current focused EditText
+ InputMethodManager? imm = (InputMethodManager?)editText.Context?.GetSystemService(Context.InputMethodService);
+ imm?.RestartInput(editText);
}
// TODO: NET8 issoto - Revisit this, marking this method as `internal` to avoid breaking public API changes