Forum Xamarin.Forms

Button loses focus after showing alert dialog [Accessibility]

JonAlzaJonAlza ESMember ✭✭✭
edited September 2020 in Xamarin.Forms

I'm developing an app for blind or visually impaired people using Xamarin.Forms. All automation properties I need are set. This app uses BLE communication with a custom device. I can set the power level of the device, only if it is switched on (if the device is switched off, you can't set de power level). In my view I have two buttons to power up and down. So when I tap the power up button when the device is off, I show an alert saying that the device is off and is going to switch on (when "accept" button tapped). When the alert is gone, the screen reader reads app's title, and the button has lost the focus. Is it the normal behavior?

I thought that when the alert went away, the button would regain focus.

I use this method to show alerts:

public async Task ShowMessage(string message, string title, string buttonText, Action afterHideCallback)
{
    await (Application.Current.MainPage as NavigationPage).CurrentPage.DisplayAlert(title, message, buttonText);
    afterHideCallback?.Invoke();
}

I'm testing with 2 smartphones with Android 6.0 and 9.0.

Do you know if it is possible to maintain the focus on the button?

Edit: It seems that the button maintains the focus in Android 9.0, but visually is not focused. So in Android 9.0 (with Samsung's Voice Assistant) it works the way I want it to. In Android 6.0, the button is visually focused, but I can't activate it with double tap. I don't know why, but it seems that in Android 9.0 doesn't work, I don't know why the previous test worked...

Best Answers

Answers

  • LeonLuLeonLu Member, Xamarin Team Xamurai

    You can try to use button.Focus(); to get the focus.

    When you click accept button in DisplayAlert, the alert will disappear, and execute afterHideCallback, you can get the focus back by button.Focus(); like following code.

     await ShowMessage("test message", "Alert", "show", () => {
    
                    button.Focus();
                });
    
  • JonAlzaJonAlza ESMember ✭✭✭

    Hello @LeonLu for your time.
    I tried calling button.Focus() method, but it returns false. I used this code:

    bool result = this.button.Focus();
    Console.WriteLine("BUTTON IS FOCUSED: " + result + " & " + this.button.IsFocused);
    

    So it doesn't work :'(

  • LeonLuLeonLu Member, Xamarin Team Xamurai
    edited September 2020

    I found button.Focus(); is an known issue for xamarin.forms, please see this thread
    https://github.com/xamarin/Xamarin.Forms/issues/5616

    the Focus method is not functional on many mobile controls (e.g., Button, WebView) because there is no native option to put focus on such native objects. This issue was reprotected in github in 2019

    However, I test with code to get the focus in custom renderer, it worked.

    [assembly: Xamarin.Forms.ExportRenderer(typeof(Xamarin.Forms.Button),typeof(App37.Droid.AndroidCustomView))]
    namespace App37.Droid
    {
       public class AndroidCustomView: ButtonRenderer
        {
            Context context;
    
            public AndroidCustomView(Context context) : base(context)
            {
                this.context = context;
            }
    
            protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
            {
                base.OnElementChanged(e);
    
                if (Control == null)
                {
                    return;
                }
    
                Console.WriteLine("created from Android");
                Control.SetBackgroundColor(Android.Graphics.Color.Red);
                Control.SetFocusable(ViewFocusability.Focusable);
                Control.FocusableInTouchMode = true;
    
    
                MessagingCenter.Subscribe<object, string>(this, "ChangeVenue", (sender, msg) =>
                {
    
                  var res=Control.RequestFocus();
    
                    if(Control.HasFocus){
                        Control.SetBackgroundColor(Android.Graphics.Color.Green);
                        Toast.MakeText(context, "getFocus",ToastLength.Long).Show();
                    }
                });
            }
    
    
        }
    

    Here is running GIF.

  • JonAlzaJonAlza ESMember ✭✭✭

    Thank you @LeonLu
    I know that in the first post I explained than a Button loses the focus, but I realized that it is an ImageButton. I tried modifying your code:

    using System;
    using Android.Content;
    using Android.Views;
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.Android;
    
    [assembly: Xamarin.Forms.ExportRenderer(typeof(Xamarin.Forms.Button), typeof(MyApp.Droid.Renderers.AndroidCustomView))]
    namespace MyApp.Droid.Renderers
    {
        class AndroidCustomView : ImageButtonRenderer
        {
            Context context;
    
            public AndroidCustomView(Context context) : base(context)
            {
                this.context = context;
            }
    
            protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ImageButton> e)
            {
                base.OnElementChanged(e);
    
                Console.WriteLine("created from Android");
                this.SetFocusable(ViewFocusability.Focusable);
                this.FocusableInTouchMode = true;
    
                MessagingCenter.Subscribe<object, string>(this, "ChangeVenue", (sender, msg) =>
                {
                    var res = this.RequestFocus();
    
                    if (this.HasFocus)
                    {
                        Toast.MakeText(context, "getFocus", ToastLength.Long).Show();
                    }
                });
            }
        }
    }
    

    I did something wrong, because when I navigate to a page with a ImageButton, I get this exception at runtime:

    Unhandled Exception:
    
    System.ArgumentException: Element is not of type Xamarin.Forms.ImageButton
    Parameter name: element occurred
    

    Do you know what is wrong?? Thank in advance.

  • LeonLuLeonLu Member, Xamarin Team Xamurai
    edited September 2020

    If you use ImageButton, you should change the value of ExportRenderer from Xamarin.Forms.Button to Xamarin.Forms.ImageButton like following assembly

    [assembly: Xamarin.Forms.ExportRenderer(typeof(Xamarin.Forms.ImageButton), typeof(MyApp.Droid.Renderers.AndroidCustomView))]

  • JonAlzaJonAlza ESMember ✭✭✭

    You are right, my mistake...

    With this renderer, when screen reader is disabled button.Focus() method works, but when screen reader is enabled it doesn't...

  • JonAlzaJonAlza ESMember ✭✭✭

    Hello @LeonLu thank you again.

    @LeonLu said:
    Do you want to achieve the result like this GIF?

    Yes, this is what I want.

    I checked it with a Samsung smartphone with Android 9. Even if the ImageButton isn't highlighted with the square, it is focused and the double tap works in it.

    But when I tried running it in LG device with Android 6, I get this exception in the this.SetFocusable(ViewFocusability.Focusable); line:

    Unhandled Exception:
    
    Java.Lang.NoSuchMethodError: no non-static method "Landroid/support/v7/widget/AppCompatImageButton;.setFocusable(I)V" occurred
    

    I checked the documentation, and this method was added in API level 26 (Android 8), but there is another setFocusable (boolean focusable) overload added in API level 1. I guess this method won't do what I need, right?

    In worst case, I will recommend Android 8 devices, and do a version check before calling the method.

  • JonAlzaJonAlza ESMember ✭✭✭
    edited September 2020

    Thank you again @LeonLu , even if setFocusable(boolean focusable) doesn't work, it is enough for our purposes.

  • LeonLuLeonLu Member, Xamarin Team Xamurai

    You are welcome.

Sign In or Register to comment.