[Android] fix focus event on android and add UI Tests (#5528)
authorShane Neuville <shane94@hotmail.com>
Fri, 15 Mar 2019 21:43:04 +0000 (15:43 -0600)
committerSamantha Houts <samhouts@users.noreply.github.com>
Fri, 15 Mar 2019 21:43:04 +0000 (14:43 -0700)
* fix focus event for material entry and add ui tests

* fix iOS

* - Focused
fixes #5509

12 files changed:
Xamarin.Forms.Controls/CoreGallery.cs
Xamarin.Forms.Controls/CoreGalleryPages/CoreGalleryPage.cs
Xamarin.Forms.Controls/ViewContainers/StateViewContainer.cs
Xamarin.Forms.Core.UITests.Shared/Tests/EntryUITests.cs
Xamarin.Forms.Core.UITests.Shared/Tests/MaterialEntryUITests.cs [new file with mode: 0644]
Xamarin.Forms.Core.UITests.Shared/Utilities/AppExtensions.cs
Xamarin.Forms.Core.UITests.Shared/Xamarin.Forms.Core.UITests.projitems
Xamarin.Forms.Material.Android/MaterialFormsTextInputLayoutBase.cs
Xamarin.Forms.Platform.Android/Cells/TextCellRenderer.cs
Xamarin.Forms.Platform.Android/ViewRenderer.cs
Xamarin.Forms.Platform.UAP/Resources.xaml
Xamarin.Forms.Platform.iOS/Cells/TextCellRenderer.cs

index df9bab3..3ef12da 100644 (file)
@@ -246,6 +246,7 @@ namespace Xamarin.Forms.Controls
        [Preserve(AllMembers = true)]
        internal class CorePageView : ListView
        {
+               [Preserve(AllMembers = true)]
                internal class GalleryPageFactory
                {
                        public GalleryPageFactory(Func<Page> create, string title)
@@ -258,11 +259,18 @@ namespace Xamarin.Forms.Controls
                                };
 
                                Title = title;
+                               TitleAutomationId = $"{Title}AutomationId";
                        }
 
                        public Func<Page> Realize { get; set; }
                        public string Title { get; set; }
 
+                       public string TitleAutomationId
+                       {
+                               get;
+                               set;
+                       }
+
                        public override string ToString()
                        {
                                // a11y: let Narrator read a friendly string instead of the default ToString()
@@ -287,7 +295,6 @@ namespace Xamarin.Forms.Controls
                                new GalleryPageFactory(() => new CellForceUpdateSizeGalleryPage(), "Cell Force Update Size Gallery"),
                                new GalleryPageFactory(() => new AppearingGalleryPage(), "Appearing Gallery"),
                                new GalleryPageFactory(() => new EntryCoreGalleryPage(), "Entry Gallery"),
-                               new GalleryPageFactory(() => new EntryCoreGalleryPage{ Visual = VisualMarker.Material }, "Entry Gallery (Material)"),
                                new GalleryPageFactory(() => new MaterialEntryGalleryPage(), "Entry Material Demos"),
                                new GalleryPageFactory(() => new NavBarTitleTestPage(), "Titles And Navbar Windows"),
                                new GalleryPageFactory(() => new PanGestureGalleryPage(), "Pan gesture Gallery"),
@@ -389,7 +396,7 @@ namespace Xamarin.Forms.Controls
                                new GalleryPageFactory(() => new TableViewGallery(), "TableView Gallery - Legacy"),
                                new GalleryPageFactory(() => new TemplatedCarouselGallery(), "TemplatedCarouselPage Gallery - Legacy"),
                                new GalleryPageFactory(() => new TemplatedTabbedGallery(), "TemplatedTabbedPage Gallery - Legacy"),
-                                new GalleryPageFactory(() => new UnevenViewCellGallery(), "UnevenViewCell Gallery - Legacy"),
+                               new GalleryPageFactory(() => new UnevenViewCellGallery(), "UnevenViewCell Gallery - Legacy"),
                                new GalleryPageFactory(() => new UnevenListGallery(), "UnevenList Gallery - Legacy"),
                                new GalleryPageFactory(() => new ViewCellGallery(), "ViewCell Gallery - Legacy"),
                                new GalleryPageFactory(() => new WebViewGallery(), "WebView Gallery - Legacy"),
@@ -428,9 +435,12 @@ namespace Xamarin.Forms.Controls
                                                }
                                        })
                                });
+
                                return cell;
                        });
+
                        template.SetBinding(TextCell.TextProperty, "Title");
+                       template.SetBinding(TextCell.AutomationIdProperty, "TitleAutomationId");
 
                        BindingContext = _pages;
                        ItemTemplate = template;
index ead8b6f..03584bd 100644 (file)
@@ -98,6 +98,19 @@ namespace Xamarin.Forms.Controls
                                _isVisibleStateViewContainer.View.IsVisible = !_isVisibleStateViewContainer.View.IsVisible;
                        });
 
+
+                       _isFocusedStateViewContainer.StateChangeButton.Command = new Command(() => {
+                               
+                               if ((bool)isFocusedView.GetValue(VisualElement.IsFocusedProperty))
+                               {
+                                       isFocusedView.SetValueCore(IsFocusedPropertyKey, false);
+                               }
+                               else
+                               {
+                                       isFocusedView.SetValueCore(IsFocusedPropertyKey, true);
+                               }
+                       });
+
                        _focusStateViewContainer.StateChangeButton.Command = new Command (() => {
                                if (_focusStateViewContainer.View.IsFocused) {
                                        _focusStateViewContainer.View.Unfocus ();
index b08cc30..4d53719 100644 (file)
@@ -24,8 +24,11 @@ namespace Xamarin.Forms.Controls
                                BindingContext = view,
                                AutomationId = name + "StateLabel"
                        };
-                       if (name != "Focus")
-                               stateValueLabel.SetBinding (Label.TextProperty, name, converter: new GenericValueConverter (o => o.ToString()));
+
+                       if(name == "Focus" || name == "Unfocused" || name == "Focused")
+                               stateValueLabel.SetBinding(Label.TextProperty, "IsFocused", converter: new GenericValueConverter(o => o.ToString()));
+                       else
+                               stateValueLabel.SetBinding (Label.TextProperty, name, converter: new GenericValueConverter (o => o.ToString()));                        
 
                        StateChangeButton = new Button {
                                Text = "Change State: " + name,
index c10c4e8..348b38a 100644 (file)
@@ -1,8 +1,10 @@
 using NUnit.Framework;
+using Xamarin.Forms.Controls.Issues;
 using Xamarin.Forms.CustomAttributes;
 
 namespace Xamarin.Forms.Core.UITests
 {
+
        [TestFixture]
        [Category(UITestCategories.Entry)]
        internal class EntryUITests : _ViewUITests
@@ -17,9 +19,20 @@ namespace Xamarin.Forms.Core.UITests
                        App.NavigateToGallery(GalleryQueries.EntryGallery);
                }
 
-               // TODO
+               [Test]
+               [UiTest(typeof(Entry), "Focus")]
                public override void _Focus()
                {
+                       var remote = new StateViewContainerRemote(App, Test.VisualElement.Focus, PlatformViewType);
+                       remote.GoTo();
+                       bool isFocused = System.Convert.ToBoolean( App.Query("FocusStateLabel")[0].ReadText());
+                       Assert.IsFalse(isFocused);
+                       remote.TapView();
+                       isFocused = System.Convert.ToBoolean(App.Query("FocusStateLabel")[0].ReadText());
+                       Assert.IsTrue(isFocused);
+                       App.Tap("FocusStateLabel");
+                       isFocused = System.Convert.ToBoolean(App.Query("FocusStateLabel")[0].ReadText());
+                       Assert.IsFalse(isFocused);
                }
 
                [UiTestExempt(ExemptReason.CannotTest, "Invalid interaction")]
@@ -27,7 +40,6 @@ namespace Xamarin.Forms.Core.UITests
                {
                }
 
-               // TODO
                public override void _IsFocused()
                {
                }
@@ -37,6 +49,8 @@ namespace Xamarin.Forms.Core.UITests
                {
                }
 
+
+               
                // TODO
                // Implement control specific ui tests
                [Test]
diff --git a/Xamarin.Forms.Core.UITests.Shared/Tests/MaterialEntryUITests.cs b/Xamarin.Forms.Core.UITests.Shared/Tests/MaterialEntryUITests.cs
new file mode 100644 (file)
index 0000000..9b83c01
--- /dev/null
@@ -0,0 +1,27 @@
+using NUnit.Framework;
+using Xamarin.Forms.Controls.Issues;
+using Xamarin.Forms.CustomAttributes;
+
+namespace Xamarin.Forms.Core.UITests
+{
+
+#if __ANDROID__ || __IOS__
+       [TestFixture]
+       [Category(UITestCategories.Entry)]
+       [Category(UITestCategories.Visual)]
+       internal class MaterialEntryUITests : EntryUITests
+       {
+               protected override void NavigateToGallery()
+               {
+                       App.NavigateToGallery(GalleryQueries.EntryGallery, "Material");
+               }
+
+               [Test]
+               [UiTest(typeof(Entry), "Focus")]
+               public override void _Focus()
+               {
+                       base._Focus();
+               }
+       }
+#endif
+}
\ No newline at end of file
index 0e6a9f4..4fedb00 100644 (file)
@@ -9,29 +9,45 @@ namespace Xamarin.Forms.Core.UITests
 {
        internal static class AppExtensions
        {
-               public static AppRect ScreenBounds (this IApp app)
+               public static AppRect ScreenBounds(this IApp app)
                {
-                       return app.Query (Queries.Root ()).First().Rect;
+                       return app.Query(Queries.Root()).First().Rect;
                }
 
-               public static void NavigateBack (this IApp app)
+               public static void NavigateBack(this IApp app)
                {
                        app.Back();
                }
 
-               public static void NavigateToGallery (this IApp app, string page)
+               public static void NavigateToGallery(this IApp app, string page)
+               {
+                       NavigateToGallery(app, page, null);
+               }
+
+               public static void NavigateToGallery(this IApp app, string page, string visual)
                {
                        const string goToTestButtonQuery = "* marked:'GoToTestButton'";
 
                        app.WaitForElement(q => q.Raw(goToTestButtonQuery), "Timed out waiting for Go To Test button to disappear", TimeSpan.FromSeconds(10));
 
-                       var text = Regex.Match (page, "'(?<text>[^']*)'").Groups["text"].Value;
+                       var text = Regex.Match(page, "'(?<text>[^']*)'").Groups["text"].Value;
 
                        app.WaitForElement("SearchBar");
-                       app.EnterText (q => q.Raw ("* marked:'SearchBar'"), text);
+                       app.EnterText(q => q.Raw("* marked:'SearchBar'"), text);
+
+                       if(!String.IsNullOrWhiteSpace(visual))
+                       {
+                               app.DismissKeyboard();
+                               app.ActivateContextMenu($"{text}AutomationId");
+                               app.Tap("Select Visual");
+                               app.Tap("Material");
+                       }
+                       else
+                       {
+                               app.Tap(q => q.Raw(goToTestButtonQuery));
+                       }
 
-                       app.Tap (q => q.Raw (goToTestButtonQuery));
-                       app.WaitForNoElement (o => o.Raw (goToTestButtonQuery), "Timed out waiting for Go To Test button to disappear", TimeSpan.FromMinutes(2));
+                       app.WaitForNoElement(o => o.Raw(goToTestButtonQuery), "Timed out waiting for Go To Test button to disappear", TimeSpan.FromMinutes(2));
                }
 
 
@@ -43,10 +59,11 @@ namespace Xamarin.Forms.Core.UITests
                        {
                                elements = app.Query(elementQuery);
                                tryCount++;
-                               if (elements.Length == 0 && onFail != null) onFail();
+                               if (elements.Length == 0 && onFail != null)
+                                       onFail();
                        }
 
                        return elements;
                }
        }
-}
+}
\ No newline at end of file
index 6dce2c4..f845986 100644 (file)
@@ -35,6 +35,7 @@
     <Compile Include="$(MSBuildThisFileDirectory)Tests\Legacy-CellsUITests.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Tests\Legacy-UnevenListTests.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Tests\MapUITests.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Tests\MaterialEntryUITests.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Tests\PickerUITests.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Tests\ProgressBarUITests.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Tests\RootGalleryUITests.cs" />
index db946f4..1d8c22a 100644 (file)
@@ -6,6 +6,8 @@ using Android.Runtime;
 using Android.Util;
 using Android.Support.V4.View;
 using Android.Content.Res;
+using AView = Android.Views.View;
+using Xamarin.Forms.Platform.Android.AppCompat;
 
 namespace Xamarin.Forms.Material.Android
 {
@@ -94,9 +96,16 @@ namespace Xamarin.Forms.Material.Android
                 * and this is the only way to set it away from that and to whatever the user specified
                 * 2) The HintTextColor has a different alpha when focused vs not focused
                 * */
-               void OnFocusChange(object sender, FocusChangeEventArgs e) => 
+               void OnFocusChange(object sender, FocusChangeEventArgs e)
+               {
                        Device.BeginInvokeOnMainThread(() => ApplyTheme());
 
+                       // propagate the focus changed event to the View Renderer base class
+                       if (Parent is AView.IOnFocusChangeListener focusChangeListener)
+                               focusChangeListener.OnFocusChange(EditText, e.HasFocus);
+
+               }
+
                internal void SetHint(string hint, VisualElement element)
                {
                        if (HintEnabled != !String.IsNullOrWhiteSpace(hint))
index 9e9ecac..3b4acc0 100644 (file)
@@ -1,3 +1,4 @@
+using System;
 using System.ComponentModel;
 using Android.Content;
 using Android.Views;
@@ -20,6 +21,7 @@ namespace Xamarin.Forms.Platform.Android
                        UpdateHeight();
                        UpdateIsEnabled();
                        UpdateFlowDirection();
+                       UpdateAutomationId();
                        View.SetImageVisible(false);
 
                        return View;
@@ -37,6 +39,13 @@ namespace Xamarin.Forms.Platform.Android
                                UpdateHeight();
                        else if (args.PropertyName == VisualElement.FlowDirectionProperty.PropertyName)
                                UpdateFlowDirection();
+                       else if (args.PropertyName == VisualElement.AutomationIdProperty.PropertyName)
+                               UpdateAutomationId();
+               }
+
+               void UpdateAutomationId()
+               {
+                       View.ContentDescription = Cell.AutomationId;
                }
 
                void UpdateDetailText()
index 42ecc78..fd75649 100644 (file)
@@ -23,6 +23,7 @@ namespace Xamarin.Forms.Platform.Android
                [Obsolete("This constructor is obsolete as of version 2.5. Please use ViewRenderer(Context) instead.")]
                [EditorBrowsable(EditorBrowsableState.Never)]
                protected ViewRenderer()
+
                {
                }
        }
@@ -37,6 +38,7 @@ namespace Xamarin.Forms.Platform.Android
                [EditorBrowsable(EditorBrowsableState.Never)]
                protected ViewRenderer() 
                {
+                       
                }
 
                protected virtual TNativeView CreateNativeControl()
index ca90517..246efe3 100644 (file)
     </Style>
 
     <DataTemplate x:Key="TextCell">
-               <StackPanel>
+               <StackPanel AutomationProperties.AutomationId="{Binding AutomationId}">
                        <TextBlock
                                Text="{Binding Text}"
                                Style="{ThemeResource BaseTextBlockStyle}"
index 7568e50..e635db9 100644 (file)
@@ -34,6 +34,7 @@ namespace Xamarin.Forms.Platform.iOS
                        UpdateBackground(tvc, item);
 
                        SetAccessibility(tvc, item);
+                       UpdateAutomationId(tvc, textCell);
 
                        return tvc;
                }
@@ -59,9 +60,15 @@ namespace Xamarin.Forms.Platform.iOS
                                tvc.DetailTextLabel.TextColor = textCell.DetailColor.ToUIColor(DefaultTextColor);
                        else if (args.PropertyName == Cell.IsEnabledProperty.PropertyName)
                                UpdateIsEnabled(tvc, textCell);
+                       else if (args.PropertyName == TextCell.AutomationIdProperty.PropertyName)
+                               UpdateAutomationId(tvc, textCell);
 
                        HandlePropertyChanged(tvc, args);
                }
+               void UpdateAutomationId(CellTableViewCell tvc, TextCell cell)
+               {
+                       tvc.AccessibilityIdentifier = cell.AutomationId;
+               }
 
                protected virtual void HandlePropertyChanged(object sender, PropertyChangedEventArgs args)
                {