[Tizen] Added support AutomationProperties (#6080)
authorKangho Hur <rookiejava@gmail.com>
Wed, 26 Jun 2019 16:10:09 +0000 (01:10 +0900)
committerRui Marinho <me@ruimarinho.net>
Wed, 26 Jun 2019 16:10:09 +0000 (17:10 +0100)
Xamarin.Forms.Controls/ControlGalleryPages/AutomationPropertiesGallery.cs
Xamarin.Forms.Platform.Tizen/Extensions/AccessibilityExtensions.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/ToolbarItemButton.cs
Xamarin.Forms.Platform.Tizen/Renderers/VisualElementRenderer.cs

index ddbc984..180e0fd 100644 (file)
@@ -56,6 +56,15 @@ namespace Xamarin.Forms.Controls
                                        boxInstructions = $"The following Box should read aloud \"{BoxName}. {BoxHelpText}\". Windows does not currently support TapGestures while the Narrator is active.";
                                        toolbarInstructions = $"The Toolbar should have a coffee cup icon. Activating the coffee cup should read aloud \"{toolbarItemName}\". The Toolbar should also show the text \"{toolbarItem2Text}\". Activating this item should read aloud \"{toolbarItem2Text}. {toolbarItemHint2}\".";
                                        break;
+                               case Device.Tizen:
+                                       screenReader = "Screen reader(TTS)";
+                                       scrollFingers = "two fingers";
+                                       explore = "Use two fingers to swipe up the screen to read all of the elements on this page.";
+                                       labeledByInstructions = $"The following Entry should read aloud \"{EntryHelpText}\", plus native instructions on how to use an Entry element. This text comes from the text of the label.";
+                                       imageInstructions = $"The following Image should read aloud \"{ImageName}. {ImageHelpText}\". Tizen does not currently support TapGestures while the\"{screenReader}\" is active.";
+                                       boxInstructions = $"Tizen does not currently support accessibility for the BoxView due to platform limitation.";
+                                       toolbarInstructions = $"The Toolbar should have a coffee cup icon. Activating the coffee cup should read aloud \"{toolbarItemName}\".";
+                                       break;
                                default:
                                        screenReader = "the native screen reader";
                                        break;
@@ -148,14 +157,17 @@ namespace Xamarin.Forms.Controls
 
                        var instructions4 = new Label { Text = imageInstructions };
                        var image = new Image { Source = "photo.jpg" };
-                       // The tap gesture will NOT work on Win
+                       // The tap gesture will NOT work on Win and Tizen
                        image.GestureRecognizers.Add(new TapGestureRecognizer { Command = new Command(() => DisplayAlert("Success", "You tapped the image", "OK")) });
                        image.SetAutomationPropertiesName(ImageName);
                        image.SetAutomationPropertiesHelpText(ImageHelpText);
+                       // Images are ignored by default on Tizen;
+                       // make accessible in order to enable the gesture and narration
+                       image.SetAutomationPropertiesIsInAccessibleTree(true);
 
-                       var instructions6 = new Label { Text = boxInstructions };
+                       var instructions5 = new Label { Text = boxInstructions };
                        var boxView = new BoxView { Color = Color.Purple };
-                       // The tap gesture will NOT work on Win
+                       // The tap gesture will NOT work on Win and Tizen
                        boxView.GestureRecognizers.Add(new TapGestureRecognizer { Command = new Command(() => DisplayAlert("Success", "You tapped the box", "OK")) });
                        boxView.SetAutomationPropertiesName(BoxName);
                        boxView.SetAutomationPropertiesHelpText(BoxHelpText);
@@ -178,7 +190,8 @@ namespace Xamarin.Forms.Controls
                                        activityIndicator,
                                        instructions4,
                                        image,
-                                       boxView
+                                       instructions5,
+                                       boxView,
                                }
                        };
 
diff --git a/Xamarin.Forms.Platform.Tizen/Extensions/AccessibilityExtensions.cs b/Xamarin.Forms.Platform.Tizen/Extensions/AccessibilityExtensions.cs
new file mode 100644 (file)
index 0000000..e953791
--- /dev/null
@@ -0,0 +1,62 @@
+using ElmSharp.Accessible;
+
+namespace Xamarin.Forms.Platform.Tizen
+{
+       public static class AccessibilityExtensions
+       {
+               public static string SetAccessibilityName(this IAccessibleObject Control, Element Element, string _defaultAccessibilityName = null)
+               {
+                       if (Element == null || Control == null)
+                               return _defaultAccessibilityName;
+
+                       if (_defaultAccessibilityName == null)
+                               _defaultAccessibilityName = Control.Name;
+
+                       Control.Name = (string)Element.GetValue(AutomationProperties.NameProperty) ?? _defaultAccessibilityName;
+                       return _defaultAccessibilityName;
+               }
+
+               public static string SetAccessibilityDescription(this IAccessibleObject Control, Element Element, string _defaultAccessibilityDescription = null)
+               {
+                       if (Element == null || Control == null)
+                               return _defaultAccessibilityDescription;
+
+                       if (_defaultAccessibilityDescription == null)
+                               _defaultAccessibilityDescription = Control.Description;
+
+                       Control.Description = (string)Element.GetValue(AutomationProperties.HelpTextProperty) ?? _defaultAccessibilityDescription;
+                       return _defaultAccessibilityDescription;
+               }
+
+               public static bool? SetIsAccessibilityElement(this IAccessibleObject Control, Element Element, bool? _defaultIsAccessibilityElement = null)
+               {
+                       if (Element == null || Control == null)
+                               return _defaultIsAccessibilityElement;
+
+                       if (!_defaultIsAccessibilityElement.HasValue)
+                               _defaultIsAccessibilityElement = Control.CanHighlight;
+
+                       Control.CanHighlight = (bool)((bool?)Element.GetValue(AutomationProperties.IsInAccessibleTreeProperty) ?? _defaultIsAccessibilityElement);
+
+                       // Images are ignored by default on Tizen. So, make accessible in order to enable the gesture and narration
+                       if (Control.CanHighlight && Element is Image)
+                       {
+                               Control.Role = AccessRole.PushButton;
+                       }
+                       return _defaultIsAccessibilityElement;
+               }
+
+               public static void SetLabeledBy(this IAccessibleObject Control, Element Element)
+               {
+                       if (Element == null || Control == null)
+                               return;
+
+                       var targetElement = (VisualElement)Element.GetValue(AutomationProperties.LabeledByProperty);
+                       AccessibleObject view = (AccessibleObject)Platform.GetRenderer(targetElement)?.NativeView;
+                       if (view != null)
+                       {
+                               Control.AppendRelation(new LabelledBy() { Target = view });
+                       }
+               }
+       }
+}
index ca23856..238452f 100644 (file)
@@ -1,5 +1,6 @@
 using System;
 using System.ComponentModel;
+using ElmSharp.Accessible;
 using EColor = ElmSharp.Color;
 
 namespace Xamarin.Forms.Platform.Tizen.Native
@@ -12,6 +13,9 @@ namespace Xamarin.Forms.Platform.Tizen.Native
                const string StyleRightToolbarButton = "naviframe/title_right";
 
                ToolbarItem _item;
+               string _defaultAccessibilityName;
+               string _defaultAccessibilityDescription;
+               bool? _defaultIsAccessibilityElement;
 
                public ToolbarItemButton(ToolbarItem item) : base(Forms.NativeParent)
                {
@@ -25,6 +29,10 @@ namespace Xamarin.Forms.Platform.Tizen.Native
                        UpdateText();
                        UpdateIsEnabled();
                        UpdateIcon();
+                       SetAccessibilityName(true);
+                       SetAccessibilityDescription(true);
+                       SetIsAccessibilityElement(true);
+                       SetLabeledBy(true);
                }
 
                void OnDeleted(object sender, EventArgs e)
@@ -53,6 +61,22 @@ namespace Xamarin.Forms.Platform.Tizen.Native
                        {
                                UpdateIcon();
                        }
+                       else if (e.PropertyName == AutomationProperties.NameProperty.PropertyName)
+                       {
+                               SetAccessibilityName(false);
+                       }
+                       else if (e.PropertyName == AutomationProperties.HelpTextProperty.PropertyName)
+                       {
+                               SetAccessibilityDescription(false);
+                       }
+                       else if (e.PropertyName == AutomationProperties.IsInAccessibleTreeProperty.PropertyName)
+                       {
+                               SetIsAccessibilityElement(false);
+                       }
+                       else if (e.PropertyName == AutomationProperties.LabeledByProperty.PropertyName)
+                       {
+                               SetLabeledBy(false);
+                       }
                }
 
                void UpdateText()
@@ -106,5 +130,53 @@ namespace Xamarin.Forms.Platform.Tizen.Native
                                Style = StyleDefault;
                        }
                }
+
+               void SetAccessibilityName(bool initialize)
+               {
+                       if (initialize && (string)_item.GetValue(AutomationProperties.NameProperty) == (default(string)))
+                               return;
+
+                       var accessibleObject = this as IAccessibleObject;
+                       if (accessibleObject != null)
+                       {
+                               _defaultAccessibilityName = accessibleObject.SetAccessibilityName(_item, _defaultAccessibilityName);
+                       }
+               }
+
+               void SetAccessibilityDescription(bool initialize)
+               {
+                       if (initialize && (string)_item.GetValue(AutomationProperties.HelpTextProperty) == (default(string)))
+                               return;
+
+                       var accessibleObject = this as IAccessibleObject;
+                       if (accessibleObject != null)
+                       {
+                               _defaultAccessibilityDescription = accessibleObject.SetAccessibilityDescription(_item, _defaultAccessibilityDescription);
+                       }
+               }
+
+               void SetIsAccessibilityElement(bool initialize)
+               {
+                       if (initialize && (bool?)_item.GetValue(AutomationProperties.IsInAccessibleTreeProperty) == default(bool?))
+                               return;
+
+                       var accessibleObject = this as IAccessibleObject;
+                       if (accessibleObject != null)
+                       {
+                               _defaultIsAccessibilityElement = accessibleObject.SetIsAccessibilityElement(_item, _defaultIsAccessibilityElement);
+                       }
+               }
+
+               void SetLabeledBy(bool initialize)
+               {
+                       if (initialize && (VisualElement)_item.GetValue(AutomationProperties.LabeledByProperty) == default(VisualElement))
+                               return;
+
+                       var accessibleObject = this as IAccessibleObject;
+                       if (accessibleObject != null)
+                       {
+                               accessibleObject.SetLabeledBy(_item);
+                       }
+               }
        }
 }
index 286b728..c9efa6e 100644 (file)
@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.ComponentModel;
 using System.Linq;
 using ElmSharp;
+using ElmSharp.Accessible;
 using Xamarin.Forms.Internals;
 using Xamarin.Forms.Platform.Tizen.Native;
 using EFocusDirection = ElmSharp.FocusDirection;
@@ -29,6 +30,9 @@ namespace Xamarin.Forms.Platform.Tizen
                VisualElementRendererFlags _flags = VisualElementRendererFlags.None;
 
                bool _movedCallbackEnabled = false;
+               string _defaultAccessibilityName;
+               string _defaultAccessibilityDescription;
+               bool? _defaultIsAccessibilityElement;
 
                Lazy<CustomFocusManager> _customFocusManager;
 
@@ -67,6 +71,10 @@ namespace Xamarin.Forms.Platform.Tizen
                        RegisterPropertyHandler(VisualElement.TabIndexProperty, UpdateTabIndex);
                        RegisterPropertyHandler(VisualElement.IsTabStopProperty, UpdateIsTabStop);
 
+                       RegisterPropertyHandler(AutomationProperties.NameProperty, SetAccessibilityName);
+                       RegisterPropertyHandler(AutomationProperties.HelpTextProperty, SetAccessibilityDescription);
+                       RegisterPropertyHandler(AutomationProperties.IsInAccessibleTreeProperty, SetIsAccessibilityElement);
+                       RegisterPropertyHandler(AutomationProperties.LabeledByProperty, SetLabeledBy);
 
                        _customFocusManager = new Lazy<CustomFocusManager>(() =>
                        {
@@ -438,6 +446,54 @@ namespace Xamarin.Forms.Platform.Tizen
                        }
                }
 
+               protected virtual void SetAccessibilityName(bool initialize)
+               {
+                       if (initialize && (string)Element.GetValue(AutomationProperties.NameProperty) == (default(string)))
+                               return;
+
+                       var accessibleObject = NativeView as IAccessibleObject;
+                       if (accessibleObject != null)
+                       {
+                               _defaultAccessibilityName = accessibleObject.SetAccessibilityName(Element, _defaultAccessibilityName);
+                       }
+               }
+
+               protected virtual void SetAccessibilityDescription(bool initialize)
+               {
+                       if (initialize && (string)Element.GetValue(AutomationProperties.HelpTextProperty) == (default(string)))
+                               return;
+
+                       var accessibleObject = NativeView as IAccessibleObject;
+                       if (accessibleObject != null)
+                       {
+                               _defaultAccessibilityDescription = accessibleObject.SetAccessibilityDescription(Element, _defaultAccessibilityDescription);
+                       }
+               }
+
+               protected virtual void SetIsAccessibilityElement(bool initialize)
+               {
+                       if (initialize && (bool?)Element.GetValue(AutomationProperties.IsInAccessibleTreeProperty) == default(bool?))
+                               return;
+
+                       var accessibleObject = NativeView as IAccessibleObject;
+                       if (accessibleObject != null)
+                       {
+                               _defaultIsAccessibilityElement = accessibleObject.SetIsAccessibilityElement(Element, _defaultIsAccessibilityElement);
+                       }
+               }
+
+               protected virtual void SetLabeledBy(bool initialize)
+               {
+                       if (initialize && (VisualElement)Element.GetValue(AutomationProperties.LabeledByProperty) == default(VisualElement))
+                               return;
+
+                       var accessibleObject = NativeView as IAccessibleObject;
+                       if (accessibleObject != null)
+                       {
+                               accessibleObject.SetLabeledBy(Element);
+                       }
+               }
+
                internal virtual void SendVisualElementInitialized(VisualElement element, EvasObject nativeView)
                {
                        element.SendViewInitialized(nativeView);