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

Commit 5fcc2c4

Browse files
committed
[Android] TalkBack now reads name and helptext on buttons.
1 parent 4cfa825 commit 5fcc2c4

File tree

5 files changed

+179
-3
lines changed

5 files changed

+179
-3
lines changed
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

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

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,7 @@
877877
<Compile Include="$(MSBuildThisFileDirectory)Issue4138.cs" />
878878
<Compile Include="$(MSBuildThisFileDirectory)Issue4314.cs" />
879879
<Compile Include="$(MSBuildThisFileDirectory)Issue3318.cs" />
880+
<Compile Include="$(MSBuildThisFileDirectory)Issue5150.cs" />
880881
<Compile Include="$(MSBuildThisFileDirectory)Issue5172.cs" />
881882
</ItemGroup>
882883
<ItemGroup>
@@ -1091,4 +1092,4 @@
10911092
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
10921093
</EmbeddedResource>
10931094
</ItemGroup>
1094-
</Project>
1095+
</Project>

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

+18-2
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)