summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Platform.Android
diff options
context:
space:
mode:
authorSamantha Houts <samantha@teamredwall.com>2017-01-31 11:49:15 -0800
committerGitHub <noreply@github.com>2017-01-31 11:49:15 -0800
commitae59382c9046501edb37882ad1c065aacce60319 (patch)
tree3578ce8e0396a38aeb8323d4051f50a19a5340fb /Xamarin.Forms.Platform.Android
parent23d228039acc504049f6a5153f5839d4c714930a (diff)
downloadxamarin-forms-ae59382c9046501edb37882ad1c065aacce60319.tar.gz
xamarin-forms-ae59382c9046501edb37882ad1c065aacce60319.tar.bz2
xamarin-forms-ae59382c9046501edb37882ad1c065aacce60319.zip
[All] Basic Accessibility Support (#713)
* [Core] Add accessibility properties * [Controls] Add accessibility gallery * [iOS] Implement accessibility properties * [Android] Implement accessibilty properties * [Win] Implement accessibility properties * [Win] Select ListView item on selected for a11y * Update docs * TODO: macOS accessibility * [iOS] Fix failing UI Tests
Diffstat (limited to 'Xamarin.Forms.Platform.Android')
-rw-r--r--Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs9
-rw-r--r--Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs4
-rw-r--r--Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs3
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs4
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs4
-rw-r--r--Xamarin.Forms.Platform.Android/ViewRenderer.cs99
-rw-r--r--Xamarin.Forms.Platform.Android/VisualElementExtensions.cs12
-rw-r--r--Xamarin.Forms.Platform.Android/VisualElementRenderer.cs77
8 files changed, 211 insertions, 1 deletions
diff --git a/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs
index 1092f767..6954654b 100644
--- a/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs
@@ -21,6 +21,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
float _defaultElevation = -1f;
float _defaultCornerRadius = -1f;
+ int? _defaultLabelFor;
bool _clickable;
bool _disposed;
@@ -106,6 +107,14 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
ContentDescription = Element.AutomationId;
}
+ void IVisualElementRenderer.SetLabelFor(int? id)
+ {
+ if (_defaultLabelFor == null)
+ _defaultLabelFor = LabelFor;
+
+ LabelFor = (int)(id ?? _defaultLabelFor);
+ }
+
VisualElementTracker IVisualElementRenderer.Tracker => _visualElementTracker;
void IVisualElementRenderer.UpdateLayout()
diff --git a/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs
index 757a98b4..85ab6b73 100644
--- a/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs
@@ -165,6 +165,10 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
_tracker = new VisualElementTracker(this);
}
+ void IVisualElementRenderer.SetLabelFor(int? id)
+ {
+ }
+
VisualElementTracker IVisualElementRenderer.Tracker => _tracker;
void IVisualElementRenderer.UpdateLayout()
diff --git a/Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs b/Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs
index 99393516..da565ce2 100644
--- a/Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs
@@ -17,6 +17,9 @@ namespace Xamarin.Forms.Platform.Android
SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint);
void SetElement(VisualElement element);
+
+ void SetLabelFor(int? id);
+
void UpdateLayout();
}
} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs
index ec9c620e..d18781a7 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs
@@ -287,6 +287,10 @@ namespace Xamarin.Forms.Platform.Android
SetDrawerLockMode(_page.IsGestureEnabled ? LockModeUnlocked : LockModeLockedClosed);
}
+ void IVisualElementRenderer.SetLabelFor(int? id)
+ {
+ }
+
void SetLockMode(int lockMode)
{
if (_currentLockMode != lockMode)
diff --git a/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs
index 6db51c23..a2e3ddb3 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs
@@ -328,6 +328,10 @@ namespace Xamarin.Forms.Platform.Android
}
}
+ void IVisualElementRenderer.SetLabelFor(int? id)
+ {
+ }
+
void UpdateBackgroundColor()
{
SetBackgroundColor(Element.BackgroundColor.ToAndroid(Color.Transparent));
diff --git a/Xamarin.Forms.Platform.Android/ViewRenderer.cs b/Xamarin.Forms.Platform.Android/ViewRenderer.cs
index c4bd3fa0..31a9c282 100644
--- a/Xamarin.Forms.Platform.Android/ViewRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/ViewRenderer.cs
@@ -19,6 +19,9 @@ namespace Xamarin.Forms.Platform.Android
}
ViewGroup _container;
+ string _defaultContentDescription;
+ bool? _defaultFocusable;
+ string _defaultHint;
bool _disposed;
EventHandler<VisualElement.FocusRequestArgs> _focusChangeHandler;
@@ -66,7 +69,7 @@ namespace Xamarin.Forms.Platform.Android
{
if (Control == null)
return (base.GetDesiredSize(widthConstraint, heightConstraint));
-
+
AView view = _container == this ? (AView)Control : _container;
view.Measure(widthConstraint, heightConstraint);
@@ -124,6 +127,8 @@ namespace Xamarin.Forms.Platform.Android
if (e.PropertyName == VisualElement.IsEnabledProperty.PropertyName)
UpdateIsEnabled();
+ else if (e.PropertyName == Accessibility.LabeledByProperty.PropertyName)
+ SetLabeledBy();
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
@@ -155,6 +160,79 @@ namespace Xamarin.Forms.Platform.Android
}
}
+ protected override void SetContentDescription()
+ {
+ if (Control == null)
+ {
+ base.SetContentDescription();
+ return;
+ }
+
+ if (Element == null)
+ return;
+
+ if (SetHint())
+ return;
+
+ if (_defaultContentDescription == null)
+ _defaultContentDescription = Control.ContentDescription;
+
+ var elemValue = string.Join(" ", (string)Element.GetValue(Accessibility.NameProperty), (string)Element.GetValue(Accessibility.HintProperty));
+
+ if (!string.IsNullOrWhiteSpace(elemValue))
+ Control.ContentDescription = elemValue;
+ else
+ Control.ContentDescription = _defaultContentDescription;
+ }
+
+ protected override void SetFocusable()
+ {
+ if (Control == null)
+ {
+ base.SetFocusable();
+ return;
+ }
+
+ if (Element == null)
+ return;
+
+ if (!_defaultFocusable.HasValue)
+ _defaultFocusable = Control.Focusable;
+
+ Control.Focusable = (bool)((bool?)Element.GetValue(Accessibility.IsInAccessibleTreeProperty) ?? _defaultFocusable);
+ }
+
+ protected override bool SetHint()
+ {
+ if (Control == null)
+ {
+ return base.SetHint();
+ }
+
+ if (Element == null)
+ return false;
+
+ var textView = Control as global::Android.Widget.TextView;
+ if (textView == null)
+ return false;
+
+ // Let the specified Title/Placeholder take precedence, but don't set the ContentDescription (won't work anyway)
+ if (((Element as Picker)?.Title ?? (Element as Entry)?.Placeholder ?? (Element as EntryCell)?.Placeholder) != null)
+ return true;
+
+ if (_defaultHint == null)
+ _defaultHint = textView.Hint;
+
+ var elemValue = string.Join(". ", (string)Element.GetValue(Accessibility.NameProperty), (string)Element.GetValue(Accessibility.HintProperty));
+
+ if (!string.IsNullOrWhiteSpace(elemValue))
+ textView.Hint = elemValue;
+ else
+ textView.Hint = _defaultHint;
+
+ return true;
+ }
+
protected void SetNativeControl(TNativeView control)
{
SetNativeControl(control, this);
@@ -219,6 +297,25 @@ namespace Xamarin.Forms.Platform.Android
Control.OnFocusChangeListener = this;
UpdateIsEnabled();
+ SetLabeledBy();
+ }
+
+ void SetLabeledBy()
+ {
+ if (Element == null || Control == null)
+ return;
+
+ var elemValue = (VisualElement)Element.GetValue(Accessibility.LabeledByProperty);
+
+ if (elemValue != null)
+ {
+ var id = Control.Id;
+ if (id == -1)
+ id = Control.Id = FormsAppCompatActivity.GetUniqueId();
+
+ var renderer = elemValue?.GetRenderer();
+ renderer?.SetLabelFor(id);
+ }
}
void UpdateIsEnabled()
diff --git a/Xamarin.Forms.Platform.Android/VisualElementExtensions.cs b/Xamarin.Forms.Platform.Android/VisualElementExtensions.cs
index 13f2fffa..800a967e 100644
--- a/Xamarin.Forms.Platform.Android/VisualElementExtensions.cs
+++ b/Xamarin.Forms.Platform.Android/VisualElementExtensions.cs
@@ -1,7 +1,19 @@
+using System;
+
namespace Xamarin.Forms.Platform.Android
{
public static class VisualElementExtensions
{
+ public static IVisualElementRenderer GetRenderer(this VisualElement self)
+ {
+ if (self == null)
+ throw new ArgumentNullException("self");
+
+ IVisualElementRenderer renderer = Platform.GetRenderer(self);
+
+ return renderer;
+ }
+
public static bool ShouldBeMadeClickable(this View view)
{
var shouldBeClickable = false;
diff --git a/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs b/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs
index 19b05e2e..46bab02e 100644
--- a/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs
@@ -23,6 +23,10 @@ namespace Xamarin.Forms.Platform.Android
VisualElementRendererFlags _flags = VisualElementRendererFlags.AutoPackage | VisualElementRendererFlags.AutoTrack;
+ string _defaultContentDescription;
+ bool? _defaultFocusable;
+ string _defaultHint;
+ int? _defaultLabelFor;
InnerGestureListener _gestureListener;
VisualElementPackager _packager;
PropertyChangedEventHandler _propertyChangeHandler;
@@ -209,6 +213,9 @@ namespace Xamarin.Forms.Platform.Android
if (element != null && !string.IsNullOrEmpty(element.AutomationId))
SetAutomationId(element.AutomationId);
+ SetContentDescription();
+ SetFocusable();
+
Performance.Stop();
}
@@ -302,6 +309,12 @@ namespace Xamarin.Forms.Platform.Android
UpdateBackgroundColor();
else if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName)
InputTransparent = Element.InputTransparent;
+ else if (e.PropertyName == Accessibility.HintProperty.PropertyName)
+ SetContentDescription();
+ else if (e.PropertyName == Accessibility.NameProperty.PropertyName)
+ SetContentDescription();
+ else if (e.PropertyName == Accessibility.IsInAccessibleTreeProperty.PropertyName)
+ SetFocusable();
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
@@ -331,6 +344,62 @@ namespace Xamarin.Forms.Platform.Android
ContentDescription = id;
}
+ protected virtual void SetContentDescription()
+ {
+ if (Element == null)
+ return;
+
+ if (SetHint())
+ return;
+
+ if (_defaultContentDescription == null)
+ _defaultContentDescription = ContentDescription;
+
+ var elemValue = string.Join(" ", (string)Element.GetValue(Accessibility.NameProperty), (string)Element.GetValue(Accessibility.HintProperty));
+
+ if (!string.IsNullOrWhiteSpace(elemValue))
+ ContentDescription = elemValue;
+ else
+ ContentDescription = _defaultContentDescription;
+ }
+
+ protected virtual void SetFocusable()
+ {
+ if (Element == null)
+ return;
+
+ if (!_defaultFocusable.HasValue)
+ _defaultFocusable = Focusable;
+
+ Focusable = (bool)((bool?)Element.GetValue(Accessibility.IsInAccessibleTreeProperty) ?? _defaultFocusable);
+ }
+
+ protected virtual bool SetHint()
+ {
+ if (Element == null)
+ return false;
+
+ var textView = this as global::Android.Widget.TextView;
+ if (textView == null)
+ return false;
+
+ // Let the specified Title/Placeholder take precedence, but don't set the ContentDescription (won't work anyway)
+ if (((Element as Picker)?.Title ?? (Element as Entry)?.Placeholder ?? (Element as EntryCell)?.Placeholder) != null)
+ return true;
+
+ if (_defaultHint == null)
+ _defaultHint = textView.Hint;
+
+ var elemValue = string.Join(". ", (string)Element.GetValue(Accessibility.NameProperty), (string)Element.GetValue(Accessibility.HintProperty));
+
+ if (!string.IsNullOrWhiteSpace(elemValue))
+ textView.Hint = elemValue;
+ else
+ textView.Hint = _defaultHint;
+
+ return true;
+ }
+
protected void SetPackager(VisualElementPackager packager)
{
_packager = packager;
@@ -357,6 +426,14 @@ namespace Xamarin.Forms.Platform.Android
UpdateGestureRecognizers();
}
+ void IVisualElementRenderer.SetLabelFor(int? id)
+ {
+ if (_defaultLabelFor == null)
+ _defaultLabelFor = LabelFor;
+
+ LabelFor = (int)(id ?? _defaultLabelFor);
+ }
+
void SubscribeGestureRecognizers(VisualElement element)
{
var view = element as View;