Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Commit b1702bc

Browse files
committed
Fix for 5150. TalkBack now reads name and helptext on buttons.
1 parent 27542f7 commit b1702bc

File tree

5 files changed

+176
-2
lines changed

5 files changed

+176
-2
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System.ComponentModel;
2+
using AViews = Android.Views;
3+
using AWidget = Android.Widget;
4+
using Xamarin.Forms;
5+
using Xamarin.Forms.ControlGallery.Android;
6+
using Xamarin.Forms.Controls.Issues;
7+
using Xamarin.Forms.Platform.Android;
8+
9+
[assembly: ExportEffect(typeof(ContentDescriptionEffectRenderer), ContentDescriptionEffect.EffectName)]
10+
namespace Xamarin.Forms.ControlGallery.Android
11+
{
12+
public class ContentDescriptionEffectRenderer : PlatformEffect
13+
{
14+
15+
protected override void OnAttached()
16+
{
17+
}
18+
19+
protected override void OnDetached()
20+
{
21+
}
22+
23+
protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
24+
{
25+
var button = Element as Button;
26+
var viewGroup = Control as AViews.ViewGroup;
27+
var nativeButton = Control as AWidget.Button;
28+
29+
if (nativeButton != null && viewGroup != null && viewGroup.ChildCount > 0)
30+
{
31+
nativeButton = viewGroup.GetChildAt(0) as AWidget.Button;
32+
}
33+
34+
if (button == null || nativeButton == null)
35+
{
36+
return;
37+
}
38+
39+
button.SetValue(
40+
ContentDescriptionEffectProperties.ContentDescriptionProperty,
41+
nativeButton.ContentDescription);
42+
}
43+
44+
}
45+
}

Xamarin.Forms.ControlGallery.Android/Xamarin.Forms.ControlGallery.Android.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
<Compile Include="_58406EffectRenderer.cs" />
122122
<Compile Include="_59457CustomRenderer.cs" />
123123
<Compile Include="_60122ImageRenderer.cs" />
124+
<Compile Include="ContentDescriptionEffectRenderer.cs" />
124125
<Compile Include="..\Xamarin.Forms.Controls\GalleryPages\OpenGLGalleries\AdvancedOpenGLGallery.cs">
125126
<Link>GalleryPages\AdvancedOpenGLGallery.cs</Link>
126127
</Compile>
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using System;
2+
using System.ComponentModel;
3+
using Xamarin.Forms.CustomAttributes;
4+
using Xamarin.Forms.Internals;
5+
6+
#if UITEST
7+
using Xamarin.Forms.Core.UITests;
8+
using Xamarin.UITest;
9+
using NUnit.Framework;
10+
#endif
11+
12+
namespace Xamarin.Forms.Controls.Issues
13+
{
14+
15+
public static class ContentDescriptionEffectProperties
16+
{
17+
public static readonly BindableProperty ContentDescriptionProperty = BindableProperty.CreateAttached(
18+
"ContentDescription",
19+
typeof(string),
20+
typeof(ContentDescriptionEffectProperties),
21+
null,
22+
propertyChanged: OnContentDescriptionChanged );
23+
24+
public static string GetContentDescription(BindableObject view)
25+
{
26+
return (string)view.GetValue(ContentDescriptionProperty);
27+
}
28+
29+
public static void SetContentDescription(BindableObject view, string value)
30+
{
31+
view.SetValue(ContentDescriptionProperty, value);
32+
}
33+
34+
static void OnContentDescriptionChanged(BindableObject bindable, object oldValue, object newValue)
35+
{
36+
System.Diagnostics.Debug.WriteLine($"Old value = {oldValue}, new value = {newValue}");
37+
}
38+
}
39+
40+
public class ContentDescriptionEffect : RoutingEffect
41+
{
42+
public const string EffectName = "ContentDescriptionEffect";
43+
44+
public ContentDescriptionEffect() : base($"{Issues.Effects.ResolutionGroupName}.{EffectName}")
45+
{
46+
}
47+
}
48+
49+
#if UITEST
50+
[Category(UITestCategories.ManualReview)]
51+
#endif
52+
[Preserve(AllMembers = true)]
53+
[Issue(IssueTracker.Github, 5150, "AutomationProperties.Name, AutomationProperties.HelpText on Button not read by Android TalkBack", PlatformAffected.Android)]
54+
public class Issue5150 : TestContentPage // or TestMasterDetailPage, etc ...
55+
{
56+
57+
private void Configure(Button button, Label label, StackLayout layout, string buttonText, string buttonName = null, string buttonHelp = null)
58+
{
59+
button.Text = buttonText;
60+
button.Effects.Add(new ContentDescriptionEffect());
61+
button.SetValue(AutomationProperties.NameProperty, buttonName);
62+
button.SetValue(AutomationProperties.HelpTextProperty, buttonHelp);
63+
button.PropertyChanged += (object sender, PropertyChangedEventArgs e) => {
64+
if (e.PropertyName == ContentDescriptionEffectProperties.ContentDescriptionProperty.PropertyName)
65+
{
66+
var element = sender as Button;
67+
var desc = (string)element.GetValue(ContentDescriptionEffectProperties.ContentDescriptionProperty);
68+
label.Text = desc;
69+
}
70+
};
71+
layout.Children.Add(button);
72+
layout.Children.Add(label);
73+
}
74+
75+
protected override void Init()
76+
{
77+
var layout = new StackLayout();
78+
79+
var ButtonWithTextAndName = new Button();
80+
var ButtonWithTextAndNameLabel = new Label();
81+
Configure(ButtonWithTextAndName, ButtonWithTextAndNameLabel, layout, "Button 1", buttonName: "Name 1");
82+
83+
var ButtonWithTextAndHelp = new Button();
84+
var ButtonWithTextAndHelpLabel = new Label();
85+
Configure(ButtonWithTextAndHelp, ButtonWithTextAndHelpLabel, layout, "Button 2", buttonHelp: "Help 2.");
86+
87+
var ButtonWithTextAndNameAndHelp = new Button();
88+
var ButtonWithTextAndNameAndHelpLabel = new Label();
89+
Configure(ButtonWithTextAndNameAndHelp, ButtonWithTextAndNameAndHelpLabel, layout, "Button 3", "Name 3", "Help 3.");
90+
91+
Content = layout;
92+
}
93+
94+
#if UITEST
95+
[Test]
96+
public void Issue5150Test()
97+
{
98+
RunningApp.Screenshot ("I am at Issue 5150");
99+
100+
RunningApp.WaitForElement (q => q.Text("Name 1"));
101+
RunningApp.Screenshot ("I see the label Name 1");
102+
103+
RunningApp.WaitForElement(q => q.Text("Button 2. Help 2."));
104+
RunningApp.Screenshot("I see the label Button 2. Help 2.");
105+
106+
RunningApp.WaitForElement(q => q.Text("Name 3. Help 3."));
107+
RunningApp.Screenshot("I see the label Name 3. Help 3.");
108+
}
109+
#endif
110+
}
111+
}

Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,7 @@
878878
<Compile Include="$(MSBuildThisFileDirectory)Issue4138.cs" />
879879
<Compile Include="$(MSBuildThisFileDirectory)Issue4314.cs" />
880880
<Compile Include="$(MSBuildThisFileDirectory)Issue3318.cs" />
881+
<Compile Include="$(MSBuildThisFileDirectory)Issue5150.cs" />
881882
</ItemGroup>
882883
<ItemGroup>
883884
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla22229.xaml">

Xamarin.Forms.Platform.Android/FastRenderers/AutomationPropertiesProvider.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ internal static void SetBasicContentDescription(
5555
defaultContentDescription = control.ContentDescription;
5656

5757
string value = ConcatenateNameAndHelpText(element);
58+
59+
var button = element as Button;
60+
if (button != null)
61+
{
62+
var viewGroup = control as global::Android.Views.ViewGroup;
63+
if (viewGroup != null)
64+
{
65+
control = viewGroup.GetChildAt(0);
66+
}
67+
}
68+
5869
control.ContentDescription = !string.IsNullOrWhiteSpace(value) ? value : defaultContentDescription;
5970
}
6071

@@ -191,12 +202,17 @@ bool SetHint()
191202

192203
internal static string ConcatenateNameAndHelpText(BindableObject Element)
193204
{
205+
var button = Element as Button;
206+
207+
var text = button?.Text;
194208
var name = (string)Element.GetValue(AutomationProperties.NameProperty);
195209
var helpText = (string)Element.GetValue(AutomationProperties.HelpTextProperty);
196210

197-
if (string.IsNullOrWhiteSpace(name))
211+
if (!string.IsNullOrWhiteSpace(text) && string.IsNullOrWhiteSpace(name))
212+
name = text;
213+
else if (string.IsNullOrWhiteSpace(name))
198214
return helpText;
199-
if (string.IsNullOrWhiteSpace(helpText))
215+
else if (string.IsNullOrWhiteSpace(helpText))
200216
return name;
201217

202218
return $"{name}. {helpText}";

0 commit comments

Comments
 (0)