Skip to content

Approach — How to send and resend accessibility focus #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions A11YTools.sln
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ Global
{DC93383E-CE5B-4B18-B3CD-39FFFA8B41DD}.Release|x86.Build.0 = Release|Any CPU
{DC93383E-CE5B-4B18-B3CD-39FFFA8B41DD}.Release|x86.Deploy.0 = Release|Any CPU
{365D53AD-E0C1-4119-8A2A-CCBF30E4440F}.Debug|Any CPU.ActiveCfg = Debug|x86
{365D53AD-E0C1-4119-8A2A-CCBF30E4440F}.Debug|Any CPU.Build.0 = Debug|x86
{365D53AD-E0C1-4119-8A2A-CCBF30E4440F}.Debug|Any CPU.Deploy.0 = Debug|x86
{365D53AD-E0C1-4119-8A2A-CCBF30E4440F}.Debug|ARM.ActiveCfg = Debug|ARM
{365D53AD-E0C1-4119-8A2A-CCBF30E4440F}.Debug|ARM.Build.0 = Debug|ARM
{365D53AD-E0C1-4119-8A2A-CCBF30E4440F}.Debug|ARM.Deploy.0 = Debug|ARM
Expand Down
1 change: 1 addition & 0 deletions A11YTools/A11YTools.Android/A11YTools.Android.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
<PackageReference Include="Xamarin.Essentials" Version="1.5.3.2" />
</ItemGroup>
<ItemGroup>
<Compile Include="AccessibleFocusBlockRenderer.cs" />
<Compile Include="PlatformEffectBase.cs" />
<Compile Include="NativeSemanticEffect.cs" />
<Compile Include="SemanticViewRenderer.cs" />
Expand Down
72 changes: 72 additions & 0 deletions A11YTools/A11YTools.Android/AccessibleFocusBlockRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using A11YTools.UWP;
using A11YTools.Views;
using Android.Content;
using Android.Views.Accessibility;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(AccessibleFocusBlock), typeof(AccessibleFocusBlockRenderer))]
namespace A11YTools.UWP
{
public class AccessibleFocusBlockRenderer : ViewRenderer<AccessibleFocusBlock, Android.Views.View>
{
private bool isFocused = false;

public AccessibleFocusBlockRenderer(Context context) : base(context)
{

}

protected override void OnElementChanged(ElementChangedEventArgs<AccessibleFocusBlock> e)
{
base.OnElementChanged(e);

if (e.NewElement != null)
{
FocusChange += Control_FocusChange;
}
else
{
FocusChange -= Control_FocusChange;
}
}

private void Control_FocusChange(object sender, FocusChangeEventArgs e)
{
if (e.HasFocus)
{
if (!isFocused)
Element?.OnAccessibilityGotFocus();

isFocused = true;
}
else
{
if (isFocused)
Element?.OnAccessibilityLostFocus();

isFocused = false;
}
}

public override void OnInitializeAccessibilityEvent(AccessibilityEvent e)
{
base.OnInitializeAccessibilityEvent(e);

if (e.EventType == EventTypes.ViewAccessibilityFocused)
{
if (!isFocused)
Element?.OnAccessibilityGotFocus();

isFocused = true;
}
else if (e.EventType == EventTypes.ViewAccessibilityFocusCleared)
{
if (isFocused)
Element?.OnAccessibilityLostFocus();

isFocused = false;
}
}
}
}
2 changes: 1 addition & 1 deletion A11YTools/A11YTools.Android/AndroidA11yService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void SetFocus(VisualElement element)
var renderer = Platform.GetRenderer(element);
var view = element.GetViewForAccessibility();

view?.SendAccessibilityEvent(EventTypes.ViewAccessibilityFocused);
view?.SendAccessibilityEvent(EventTypes.ViewFocused);
}

public void SetAnnouncement(string text)
Expand Down
7 changes: 7 additions & 0 deletions A11YTools/A11YTools.UWP/A11YTools.UWP.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<ItemGroup>
<Compile Include="AccessibleFocusBlockRenderer.cs" />
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
Expand All @@ -98,6 +99,7 @@
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SemanticViewRenderer.cs" />
<Compile Include="UWPA11yService.cs" />
</ItemGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
Expand Down Expand Up @@ -162,4 +164,9 @@
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<UserProperties XamarinHotReloadXFormsNugetUpgradeInfoBarA11YToolsUWPHideInfoBar="True" />
</VisualStudio>
</ProjectExtensions>
</Project>
81 changes: 81 additions & 0 deletions A11YTools/A11YTools.UWP/AccessibleFocusBlockRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using A11YTools.UWP;
using A11YTools.Views;
using System.ComponentModel;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Xamarin.Forms.Platform.UWP;

[assembly: ExportRenderer(typeof(AccessibleFocusBlock), typeof(AccessibleFocusBlockRenderer))]
namespace A11YTools.UWP
{
public class AccessibleFocusBlockRenderer : ViewRenderer<AccessibleFocusBlock, Windows.UI.Xaml.Controls.Button>
{
private Windows.UI.Xaml.Controls.Button accessibilityHiddenBtn = null;

protected override void OnElementChanged(ElementChangedEventArgs<AccessibleFocusBlock> e)
{
base.OnElementChanged(e);

if (e.OldElement != null && accessibilityHiddenBtn != null)
{
accessibilityHiddenBtn.GotFocus -= AccessibilityHiddenBtn_GotFocus;
accessibilityHiddenBtn.LostFocus -= AccessibilityHiddenBtn_LostFocus;
accessibilityHiddenBtn = null;

SetNativeControl(null);
}

if (e.NewElement != null)
{
accessibilityHiddenBtn = new Windows.UI.Xaml.Controls.Button();
accessibilityHiddenBtn.IsTabStop = e.NewElement.IsTabStop;
accessibilityHiddenBtn.IsHitTestVisible = false;
accessibilityHiddenBtn.IsEnabled = false;
accessibilityHiddenBtn.Visibility = e.NewElement.IsTabStop && e.NewElement.IsEnabled && e.NewElement.IsVisible ? Visibility.Visible : Visibility.Collapsed;
accessibilityHiddenBtn.UseSystemFocusVisuals = false;
accessibilityHiddenBtn.GotFocus += AccessibilityHiddenBtn_GotFocus;
accessibilityHiddenBtn.LostFocus += AccessibilityHiddenBtn_LostFocus;
Canvas.SetZIndex(accessibilityHiddenBtn, -1);

SetNativeControl(accessibilityHiddenBtn);
}
}

protected override void Dispose(bool disposing)
{
if (disposing && Control != null)
{
accessibilityHiddenBtn.GotFocus -= AccessibilityHiddenBtn_GotFocus;
accessibilityHiddenBtn.LostFocus -= AccessibilityHiddenBtn_LostFocus;
accessibilityHiddenBtn = null;

SetNativeControl(null);
}
base.Dispose(disposing);
}

protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);

switch (e.PropertyName)
{
case nameof(Element.IsEnabled):
case nameof(Element.IsTabStop):
case nameof(Element.IsVisible):
accessibilityHiddenBtn.Visibility = Element.IsTabStop && Element.IsEnabled && Element.IsVisible ? Visibility.Visible : Visibility.Collapsed;
break;
}
}

private void AccessibilityHiddenBtn_GotFocus(object sender, RoutedEventArgs e)
{
Element?.OnAccessibilityGotFocus();
}

private void AccessibilityHiddenBtn_LostFocus(object sender, RoutedEventArgs e)
{
Element?.OnAccessibilityLostFocus();
}
}
}
52 changes: 52 additions & 0 deletions A11YTools/A11YTools.UWP/UWPA11yService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using A11YTools.UWP;
using A11YTools.Views;
using System;
using System.Diagnostics;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Input;
using Xamarin.Forms;
using Xamarin.Forms.Platform.UWP;

[assembly: Dependency(typeof(UWPA11yService))]
namespace A11YTools.UWP
{
public class UWPA11yService : IA11yService
{
public void SetAnnouncement(string text)
{
throw new NotImplementedException();
}

public void SetControlType(VisualElement element, ControlType controlType)
{
throw new NotImplementedException();
}

public async void SetFocus(VisualElement element)
{
var containerElement = Platform.GetRenderer(element).ContainerElement;

FrameworkElement view = null;
if (containerElement is AccessibleFocusBlockRenderer)
{
view = ((Xamarin.Forms.Platform.UWP.VisualElementRenderer<A11YTools.Views.AccessibleFocusBlock, Windows.UI.Xaml.Controls.Button>)containerElement).Control;
}
if (containerElement is ButtonRenderer)
{
view = ((VisualElementRenderer<Xamarin.Forms.Button, Xamarin.Forms.Platform.UWP.FormsButton>)containerElement).Control;
}

if (view == null)
throw new NotImplementedException();

var result = await FocusManager.TryFocusAsync(view, FocusState.Programmatic);

Debug.WriteLine($"Set focus result {result.Succeeded}");
}

public void SetIsClickable(VisualElement element, bool isClickable, Action clickActionThatOnlyRunsOnAndroid)
{
throw new NotImplementedException();
}
}
}
17 changes: 17 additions & 0 deletions A11YTools/A11YTools/Views/AccessibleFocusBlock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Xamarin.Forms;

namespace A11YTools.Views
{
public class AccessibleFocusBlock : ContentView
{
public virtual void OnAccessibilityGotFocus()
{

}

public virtual void OnAccessibilityLostFocus()
{

}
}
}
44 changes: 37 additions & 7 deletions A11YTools/A11YTools/Views/SetFocus.xaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,45 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="A11YTools.Views.SetFocus">
x:Class="A11YTools.Views.SetFocus"
xmlns:local="clr-namespace:A11YTools.Views">
<ContentPage.Content>

<StackLayout>
<Label x:Name="theLabel" Text="Hello I am the Label"></Label>
<Button
Text="Set Accessibility Focus To Label"
Clicked="Button_Clicked"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />

<local:AccessibleFocusBlock x:Name="afcLabel"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.LabeledBy="{x:Reference theLabel}">
<Label x:Name="theLabel"
Text="Hello I am the Label" />
</local:AccessibleFocusBlock>

<local:AccessibleFocusBlock x:Name="afcLabel2"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.LabeledBy="{x:Reference theLabel2}">
<Label x:Name="theLabel2"
Text="Hello I am the Label 2" />
</local:AccessibleFocusBlock>

<Button x:Name="theButton1"
Text="Set Accessibility Focus To Label"
Clicked="Button_Clicked"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />

<Button x:Name="theButton2"
Text="Set Accessibility Focus To Label 2"
Clicked="Button2_Clicked"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />

<Button x:Name="theButton3"
Text="Set Accessibility Focus To Button 1"
Clicked="Button3_Clicked"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />

</StackLayout>

</ContentPage.Content>
</ContentPage>
15 changes: 10 additions & 5 deletions A11YTools/A11YTools/Views/SetFocus.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;
Expand All @@ -21,7 +17,16 @@ public SetFocus()

private void Button_Clicked(object sender, EventArgs e)
{
_a11yService.SetFocus(theLabel);
_a11yService.SetFocus(afcLabel);
}
private void Button2_Clicked(object sender, EventArgs e)
{
_a11yService.SetFocus(afcLabel2);
}

private void Button3_Clicked(object sender, EventArgs e)
{
_a11yService.SetFocus(theButton1);
}
}
}