[Android] Handle accessibility importance when using modal pages (#4404) fixes #3622
authorRui Marinho <me@ruimarinho.net>
Thu, 29 Nov 2018 12:14:23 +0000 (12:14 +0000)
committerGitHub <noreply@github.com>
Thu, 29 Nov 2018 12:14:23 +0000 (12:14 +0000)
* [Controls] Add repo for issue #3622

* [Android] Handle accessibility importance when using modal pages

* [Controls] Use default styles

* Update Xamarin.Forms.Platform.Android/AppCompat/Platform.cs

Co-Authored-By: rmarinho <me@ruimarinho.net>
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue3622.cs [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
Xamarin.Forms.Platform.Android/AppCompat/Platform.cs

diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue3622.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue3622.cs
new file mode 100644 (file)
index 0000000..3e418ff
--- /dev/null
@@ -0,0 +1,217 @@
+using System;
+using System.Collections.Generic;
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+
+#if UITEST
+using Xamarin.Forms.Core.UITests;
+using Xamarin.UITest;
+using NUnit.Framework;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+#if UITEST
+       [Category(UITestCategories.ManualReview)]
+#endif
+       [Preserve(AllMembers = true)]
+       [Issue(IssueTracker.Github, 3622, "Android TalkBack reads elements behind modal pages", PlatformAffected.Android, NavigationBehavior.PushModalAsync)]
+       public class Issue3622 : TestContentPage // or TestMasterDetailPage, etc ...
+       {
+               [Preserve(AllMembers = true)]
+               public class Contact
+               {
+                       public string Name { get; set; }
+
+                       public int Age { get; set; }
+
+                       public string Occupation { get; set; }
+
+                       public string Country { get; set; }
+
+                       public override string ToString()
+                       {
+                               return Name;
+                       }
+               }
+
+               [Preserve(AllMembers = true)]
+               public class DetailPageCS : ContentPage
+               {
+                       public DetailPageCS()
+                       {
+                               var nameLabel = new Label
+                               {
+                                       Style = Device.Styles.TitleStyle
+                               };      
+                               nameLabel.SetBinding(Label.TextProperty, "Name");
+
+                               var ageLabel = new Label
+                               {
+                                       Style = Device.Styles.CaptionStyle
+
+                               };
+                               ageLabel.SetBinding(Label.TextProperty, "Age");
+
+                               var occupationLabel = new Label
+                               {
+                                       Style = Device.Styles.BodyStyle
+                               };
+                               occupationLabel.SetBinding(Label.TextProperty, "Occupation");
+
+                               var countryLabel = new Label
+                               {
+                                       FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
+                                       FontAttributes = FontAttributes.Bold
+                               };
+                               countryLabel.SetBinding(Label.TextProperty, "Country");
+
+                               var dismissButton = new Button { Text = "Dismiss" };
+                               dismissButton.Clicked += OnDismissButtonClicked;
+
+                               Content = new StackLayout
+                               {
+                                       HorizontalOptions = LayoutOptions.Center,
+                                       VerticalOptions = LayoutOptions.Center,
+                                       Children = {
+                                       new StackLayout {
+                                               Orientation = StackOrientation.Horizontal,
+                                               Children = {
+                                                       new Label {
+                                                               Text = "Name:",
+                                                               FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
+                                                               HorizontalOptions = LayoutOptions.FillAndExpand
+                                                       },
+                                                       nameLabel
+                                               }
+                                       },
+                                       new StackLayout {
+                                               Orientation = StackOrientation.Horizontal,
+                                               Children = {
+                                                       new Label {
+                                                               Text = "Age:",
+                                                               FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
+                                                               HorizontalOptions = LayoutOptions.FillAndExpand
+                                                       },
+                                                       ageLabel
+                                               }
+                                       },
+                                       new StackLayout {
+                                               Orientation = StackOrientation.Horizontal,
+                                               Children = {
+                                                       new Label {
+                                                               Text = "Occupation:",
+                                                               FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
+                                                               HorizontalOptions = LayoutOptions.FillAndExpand
+                                                       },
+                                                       occupationLabel
+                                               }
+                                       },
+                                       new StackLayout {
+                                               Orientation = StackOrientation.Horizontal,
+                                               Children = {
+                                                       new Label {
+                                                               Text = "Country:",
+                                                               FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
+                                                               HorizontalOptions = LayoutOptions.FillAndExpand
+                                                       },
+                                                       countryLabel
+                                               }
+                                       },
+                                       dismissButton
+                               }
+                               };
+                       }
+
+                       async void OnDismissButtonClicked(object sender, EventArgs args)
+                       {
+                               await Navigation.PopModalAsync();
+                       }
+               }
+
+               ListView listView;
+               List<Contact> contacts;
+
+               protected override void Init()
+               {
+                       SetupData();
+
+                       listView = new ListView
+                       {
+                               Header = new Label { Text = "Enable TalkBack. Make sure Android reads this list, when you tap an item make sure it reads the details page and not this list" },
+                               ItemsSource = contacts
+                       };
+                       listView.ItemSelected += OnItemSelected;
+
+                       Thickness padding;
+                       switch (Device.RuntimePlatform)
+                       {
+                               case Device.iOS:
+                                       padding = new Thickness(0, 40, 0, 0);
+                                       break;
+                               default:
+                                       padding = new Thickness();
+                                       break;
+                       }
+
+                       Padding = padding;
+                       Content = new StackLayout
+                       {
+                               Children = {
+                                       listView
+                               }
+                       };
+               }
+
+               async void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
+               {
+                       if (listView.SelectedItem != null)
+                       {
+                               var detailPage = new DetailPageCS();
+                               detailPage.BindingContext = e.SelectedItem as Contact;
+                               listView.SelectedItem = null;
+                               await Navigation.PushModalAsync(detailPage);
+                       }
+               }
+
+               void SetupData()
+               {
+                       contacts = new List<Contact>();
+                       contacts.Add(new Contact
+                       {
+                               Name = "Jane Doe",
+                               Age = 30,
+                               Occupation = "Developer",
+                               Country = "USA"
+                       });
+                       contacts.Add(new Contact
+                       {
+                               Name = "John Doe",
+                               Age = 34,
+                               Occupation = "Tester",
+                               Country = "USA"
+                       });
+                       contacts.Add(new Contact
+                       {
+                               Name = "John Smith",
+                               Age = 52,
+                               Occupation = "PM",
+                               Country = "UK"
+                       });
+                       contacts.Add(new Contact
+                       {
+                               Name = "Kath Smith",
+                               Age = 55,
+                               Occupation = "Business Analyst",
+                               Country = "UK"
+                       });
+                       contacts.Add(new Contact
+                       {
+                               Name = "Steve Smith",
+                               Age = 19,
+                               Occupation = "Junior Developer",
+                               Country = "UK"
+                       });
+               }
+       }
+}
\ No newline at end of file
index 3aa679f..424c486 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)Controls\ContactsPage.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Controls\FailImageSource.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Controls\ICacheService.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Issue3622.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Issue4138.cs" />
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue4194.xaml">
       <SubType>Designer</SubType>
-      <Generator>MSBuild:Compile</Generator>
+      <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
     </EmbeddedResource>
   </ItemGroup>
   <ItemGroup>
index 9e85056..13b5803 100644 (file)
@@ -115,6 +115,8 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                                }
                        }
 
+                       UpdateAccessibilityImportance(CurrentPageController as Page, ImportantForAccessibility.Auto, true);
+
                        return source.Task;
                }
 
@@ -146,6 +148,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                async Task INavigation.PushModalAsync(Page modal, bool animated)
                {
                        CurrentPageController?.SendDisappearing();
+                       UpdateAccessibilityImportance(CurrentPageController as Page, ImportantForAccessibility.NoHideDescendants, false);
 
                        _navModel.PushModal(modal);
 
@@ -153,6 +156,8 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
 
                        await presentModal;
 
+                       UpdateAccessibilityImportance(modal, ImportantForAccessibility.Auto, true);
+
                        // Verify that the modal is still on the stack
                        if (_navModel.CurrentPage == modal)
                                ((IPageController)modal).SendAppearing();
@@ -262,6 +267,18 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                        }
                }
 
+               void UpdateAccessibilityImportance(Page page, ImportantForAccessibility importantForAccessibility, bool forceFocus)
+               {
+
+                       var pageRenderer = Android.Platform.GetRenderer(page);
+                       if (pageRenderer?.View == null)
+                               return;
+                       pageRenderer.View.ImportantForAccessibility = importantForAccessibility;
+                       if (forceFocus)
+                               pageRenderer.View.SendAccessibilityEvent(global::Android.Views.Accessibility.EventTypes.ViewFocused);
+                       
+               }
+
                void SetPageInternal(Page newRoot)
                {
                        var layout = false;
@@ -455,4 +472,4 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
 
                #endregion
        }
-}
\ No newline at end of file
+}