Xamarin.Forms icon indicating copy to clipboard operation
Xamarin.Forms copied to clipboard

[Bug] [Android] Keyboard.Numeric: It's not possible to enter the decimal separator or the minus sign

Open omghb opened this issue 6 years ago • 22 comments

Description

I have set the Keyboard to the Numeric Keyboard for some Entry controls.

<Entry Keyboard="Numeric" ...

On Samsung phones and tablets it is not possible to enter the decimal separator or the minus sign. I believe the minus sign does not work at all.

Important for reproduction: Change the language/locale to German/Germany. In Germany the separator sign is ',' (comma) instead of '.' (point).

Responsible code:

The EntryCellRenderer creates it's own DigitsKeyListener for Numeric Keyboard: https://github.com/xamarin/Xamarin.Forms/blob/bd31e1e9fc8b2f9ad94cc99e0c7ab058174821f3/Xamarin.Forms.Platform.Android/Cells/EntryCellRenderer.cs#L72

The LocalizedDigitsKeyListener is only used when the 'decimalSeparator' is not '.'. The bug is only seen when the LocalizedDigitsKeyListener is used. https://github.com/xamarin/Xamarin.Forms/blob/bd31e1e9fc8b2f9ad94cc99e0c7ab058174821f3/Xamarin.Forms.Platform.Android/Renderers/LocalizedDigitsKeyListener.cs#L56

Seen issues:

  • On Samsung devices the numeric keyboard shows always '.' (point) as decimal separator. It does not provide the correct decimal separator ',' (comma) for Germany. Pressing the '.' does not even add the character to the Entry control because it is prevented (filtered) by the LocalizedDigitsKeyListener.
  • When the LocalizedDigitsKeyListener is used I'm not able to add the minus character.

Workaround

I wrote my own renderer for the entry. I return always the Android version of the DigitsKeyListener. The Xamarin implementation uses the depricated DigitsKeyListener.GetInstance overload without the Locale parameter. I use the one with the Locale parameter and pass Locale.Default. Maybe it would even be better to get the Locale from CultureInfo.CurrentCulture but that is not trivial.

internal class MyEntryRenderer : EntryRenderer
{
    public MyEntryRenderer(Context context) : base(context) { }

    protected override NumberKeyListener GetDigitsKeyListener(InputTypes inputTypes)
    {
        return DigitsKeyListener.GetInstance(Java.Util.Locale.Default, 
            inputTypes.HasFlag(InputTypes.NumberFlagSigned),
            inputTypes.HasFlag(InputTypes.NumberFlagDecimal));
    }
}

Context

  • Version with issue: Xamarin.Forms 4.0.0.497661
  • Platform Target Frameworks:
    • Android: 8.1
  • Affected Devices:
    • Samsung phones and tablets (checked with Android 8.1 and Android 9)

omghb avatar Jun 19 '19 11:06 omghb

Similar to #6580, this would be a breaking change, so it would need to be implemented as a new option. If you'd like to submit a PR, we'd love to review it! Thanks!

samhouts avatar Jun 21 '19 01:06 samhouts

@samhouts

  • The issue #6580 sounds similar to this one but I believe that they are different when looking at the details.
  • In my opinion there is a bug in the LocalizedDigitsKeyListener class that prevents the usage of the minus key. Please keep in mind that the LocalizedDigitsKeyListener class is only used when the decimal separator is not the point '.'. You could change the language to German/Germany to reproduce it because then the decimal separator is the comma ','.
  • Samsung Android provides always a numeric keyboard with '.' (point) as decimal separator independent of the language setting. On a Samsung device where the language set to German/Germany the LocalizedDigitsKeyListener prevents entering the '.' (point) at all. Therefore, it is difficult to develop a workaround (e.g. DoubleValueConverter).
  • Unfortunately, I do not have the time to develop a PR.

omghb avatar Jun 21 '19 18:06 omghb

Also run into the same problem. This is a very old issue and very annoying bug. Please fix or improve this soon. Writing Apps for an international customer base gets very disappointing with this bug.

maexsp avatar Oct 14 '19 14:10 maexsp

I also have the same problem on a Motorola Moto G (5S) Plus with Android 8.1. Our Customers are in Austria so the locale ist set to de-AT.

The workaround with the custom renderer does not work for me since I use Xamarin.Forms Material Visual! And also if you have a databinding to a double this influences the entry-control in this way that the decimal-separator character is changed from a dot '.' to a comma ','!

I really need a fix very urgently! So when will this issue be fixed?

Heinz12 avatar Mar 05 '20 10:03 Heinz12

Same issue here. I implemented a slider instead of an entry and customers go mad because of this :/

nebula2 avatar Mar 19 '20 18:03 nebula2

I tested on a Samsung J5, Android 6.0 API Version 23. Worked just fine with locale set to PT-BR and EN-US. However, on a Samsung J7 (2018), Android 9.0, locale PT-BR, the bug still happens. The user cannot click on dot neither comma to enter decimal places.

cesarau41 avatar Apr 16 '20 02:04 cesarau41

The workaround with the custom renderer does not work for me since I use Xamarin.Forms Material Visual!

@Heinz12 you could do it with the MaterialEntryRenderer instead of EntryRenderer, as specified in the doc https://docs.microsoft.com/fr-fr/xamarin/xamarin-forms/user-interface/visual/material-visual

galactose310 avatar Apr 17 '20 07:04 galactose310

That is right. I already did this. Thanks ;-)

Heinz12 avatar Apr 17 '20 07:04 Heinz12

I found a workaround for this issue. it may not be considered as a clean solution but it does the job.

I ended up using a ValueConverter.

using System.Globalization;

namespace TT2Master.ValueConverter
{
    /// <summary>
    /// Converts double to user friendly number
    /// </summary>
    public class DoubleValueConverter : BaseValueConverter<DoubleValueConverter>
    {
        /// <summary>
        /// Convert anything to double
        /// </summary>
        /// <param name="value">value to convert</param>
        /// <param name="targetType">not supported</param>
        /// <param name="parameter">not supported</param>
        /// <param name="culture">not supported</param>
        /// <returns>double</returns>
        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
            {
                return 0;
            }
            else
            {
                return TypeConverter.ForceDoubleUniversal(
                    (value.ToString().EndsWith(".") || value.ToString().EndsWith(",")) 
                    ? value.ToString() + "0" 
                    : value.ToString());
            }
        }

        public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => Convert(value, targetType, parameter, culture);
    }
}

Where BaseValueConverter is

using System.Globalization;
using Xamarin.Forms;

namespace TT2Master.ValueConverter
{
    /// <summary>
    /// base value converter
    /// </summary>
    /// <typeparam name="T">The type of this value converter</typeparam>
    public abstract class BaseValueConverter<T> : IValueConverter
        where T : class, new()
    {
        #region Value Converter Methods
        /// <summary>
        /// The method to convert one type to another
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);

        /// <summary>
        /// The method to convert a value back to itself
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public abstract object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);

        #endregion
    }
}

Usage example in your page or whatever:

  1. add xmlns if needed xmlns:converter="clr-namespace:TT2Master.ValueConverter"

  2. Add converter to resource dictionary

    <pages:PopupPage.Resources>
        <ResourceDictionary>
            <converter:DoubleValueConverter x:Key="DoubleConverter" />
        </ResourceDictionary>
    </pages:PopupPage.Resources>
  1. Use converter <Entry Grid.Row="8" Grid.Column="2" Text="{Binding MinEfficiency, Converter={StaticResource DoubleConverter}, Mode=TwoWay}" Keyboard="Numeric"/>

Hope this helps :)

nebula2 avatar Apr 30 '20 14:04 nebula2

@nebula2 Where is ForceDoubleUniversal coming from?

Dids avatar Jun 17 '20 11:06 Dids

@Dids > @nebula2 Where is ForceDoubleUniversal coming from?

Sorry, ForceDoubleUniversal is just this here:

/// <summary>
/// Forces conversion from object to double
/// </summary>
/// <param name="o"></param>
/// <returns></returns>
public static double ForceDoubleUniversal(object o)
{
    if(o == null)
    {
        return 0;
    }
    var culture = o.ToString().Contains(",") ? CultureInfo.CreateSpecificCulture("de-DE") : CultureInfo.CreateSpecificCulture("en-US");

    return !Double.TryParse(o.ToString(), NumberStyles.Any, culture, out double result) ? 0 : result;
}

nebula2 avatar Jul 07 '20 18:07 nebula2

It's very sad to see that this is still not fixed. This is not the only bug related to locales in Xamarin. Is this a US-only framework?

@omghb, is your workaround still valid in Xamarin Forms 4.8? Because when I use it, the default keyboard is shown instead of the numeric keyboard.

@nebula2, just to confirm, your workaround doesn't work on Samsung devices, right? Since dots aren't even coming to the control.

SWarnberg avatar Oct 28 '20 08:10 SWarnberg

It's very sad to see that this is still not fixed. This is not the only bug related to locales in Xamarin. Is this a US-only framework?

@nebula2, just to confirm, your workaround doesn't work on Samsung devices, right? Since dots aren't even coming to the control.

I am using a Huawei phone. but I have an old Samsung S5. I will try and see if that works there. If not it would mean a small adjustment. i am using this value converter in prod and had no issues until today

nebula2 avatar Oct 28 '20 08:10 nebula2

Any progress here? All de-DE xamarin app users with samsung phones are affected. I'm pretty sure they'll appreciate if they can start using decimal separators in Germany...

thomasgalliker avatar Dec 01 '20 19:12 thomasgalliker

@samhouts This bug affects a huge amount of locales. Just have a look on this map showing usage of dot vs. comma all over the world. https://en.wikipedia.org/wiki/Decimal_separator grafik

maexsp avatar Dec 03 '20 07:12 maexsp

@samhouts This bug affects a huge amount of locales. Just have a look on this map showing usage of dot vs. comma all over the world. https://en.wikipedia.org/wiki/Decimal_separator grafik

I can confirm this issue still exists in Xamarin.Forms 5.0.0. As this only affects the Samsung keyboard, is this not a specific issue with the Samsung keyboard itself? Or is it really Xamarin that has to specify the required input options more clearly to the OS?

timvandenhof avatar Jan 25 '21 12:01 timvandenhof

Another workaround is to install and switch to "Gboard". Screenshot_20210623-Gboard

roman536 avatar Jun 23 '21 10:06 roman536

@roman536 this is indeed a valid workaround. However, many mobile users don't even know that there is more than one keyboard available :)

thomasgalliker avatar Jun 23 '21 11:06 thomasgalliker

In my opinion it is not a valid workaround to get every user reconfigure the default system keyboard.

Furthermore, I want to repeat that this is a XAMARIN BUG in the LocalizedDigitsKeyListener implementation. Anyway the whole design of the LocalizedDigitsKeyListener looks quite suspicious to me. I also provide a simple workaround. Please have a look at my initial post.

The LocalizedDigitsKeyListener is only used when the 'decimalSeparator' is not '.'. The bug is only seen when the LocalizedDigitsKeyListener is used.

omghb avatar Jun 28 '21 06:06 omghb

Still existing bug. And if I want to use DisplayPromptAsync with Keyboard.Numeric how can I figure it out then? In my country with Samsung only device minus sign and dot separator are even non clickable.

TimurVa avatar Jan 19 '22 07:01 TimurVa

we also stumbled over the same problem; are there plans to get this fixed?

pauljereb avatar Mar 15 '22 08:03 pauljereb

This is Still an issue with the Samsung Keyboard, maybe its time to abandon Xamarin altogether........ seems like they are not interested in fixing this at all!

DrewWeird avatar Sep 06 '22 05:09 DrewWeird

This is Still an issue with the Samsung Keyboard, maybe its time to abandon Xamarin altogether........ seems like they are not interested in fixing this at all!

This is between Android <-> OEM. I saw this bug on other phones too, not only Samsung. So more like Android thingy. And don't be fooled that some other framework has it working, e.g.: https://github.com/flutter/flutter/issues/61175

kristianpinke avatar Dec 02 '22 15:12 kristianpinke