From 69d7cb4ba273ddcaa3073e682296121ecd658aed Mon Sep 17 00:00:00 2001 From: "Jon Thysell (JAUNTY)" Date: Fri, 16 Jun 2023 14:15:44 -0700 Subject: [PATCH 1/9] Fix accessibilityState to support states not being set Our existing implementation for `accessibilityState` does not support that the values of a state can be `null`. This means *every* View has *every* unset state with the default `false` value. The problem stems from implementing the short-lived `accessibilityStates` prop at the same time. This PR fixes our implementation to only include the states when explicitly set. Resolves #11791 --- .../Views/DynamicAutomationPeer.cpp | 69 +----- .../Views/DynamicAutomationPeer.h | 1 - .../Views/DynamicAutomationProperties.cpp | 51 +---- .../Views/DynamicAutomationProperties.h | 12 +- .../FrameworkElementTransferProperties.cpp | 8 - .../Views/FrameworkElementViewManager.cpp | 203 ++++++++++-------- .../Views/cppwinrt/DynamicAutomationPeer.idl | 21 +- 7 files changed, 146 insertions(+), 219 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.cpp b/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.cpp index 9f92d3b340f..0b20562805c 100644 --- a/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.cpp +++ b/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.cpp @@ -122,13 +122,11 @@ winrt::IInspectable DynamicAutomationPeer::GetPatternCore(winrt::PatternInterfac accessibilityRole == winrt::Microsoft::ReactNative::AccessibilityRoles::Switch || accessibilityRole == winrt::Microsoft::ReactNative::AccessibilityRoles::Radio || accessibilityRole == winrt::Microsoft::ReactNative::AccessibilityRoles::ToggleButton) && - (HasAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Checked) || - HasAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Unchecked))) { + HasAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Checked)) { return *this; } else if ( patternInterface == winrt::PatternInterface::ExpandCollapse && - (HasAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Expanded) || - HasAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Collapsed))) { + HasAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Expanded)) { return *this; } else if ( patternInterface == winrt::PatternInterface::Value && @@ -154,8 +152,7 @@ winrt::IInspectable DynamicAutomationPeer::GetPatternCore(winrt::PatternInterfac } bool DynamicAutomationPeer::IsEnabledCore() const { - bool disabled = HasAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Disabled) && - GetAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Disabled); + bool disabled = DynamicAutomationProperties::GetAccessibilityStateDisabled(Owner()); return !disabled && Super::IsEnabledCore(); } @@ -163,8 +160,7 @@ winrt::hstring DynamicAutomationPeer::GetItemStatusCore() const { winrt::hstring itemStatus = Super::GetItemStatusCore(); if (itemStatus.empty()) { - if (HasAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Busy) && - GetAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Busy)) { + if (DynamicAutomationProperties::GetAccessibilityStateBusy(Owner())) { itemStatus = L"Busy"; } } @@ -195,7 +191,7 @@ winrt::com_array DynamicAutomationPeer::GetSel // ISelectionItemProvider bool DynamicAutomationPeer::IsSelected() const { - return GetAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Selected); + return DynamicAutomationProperties::GetAccessibilityStateSelected(Owner()); } winrt::IRawElementProviderSimple DynamicAutomationPeer::SelectionContainer() const { @@ -222,16 +218,9 @@ void DynamicAutomationPeer::Select() const { // IToggleProvider winrt::ToggleState DynamicAutomationPeer::ToggleState() const { - bool checkedState = GetAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Checked); - bool uncheckedState = GetAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Unchecked); + auto checkedState = DynamicAutomationProperties::GetAccessibilityStateChecked(Owner()); - if (!checkedState && uncheckedState) { - return winrt::ToggleState::Off; - } else if (checkedState && !uncheckedState) { - return winrt::ToggleState::On; - } - - return winrt::ToggleState::Indeterminate; + return static_cast(checkedState); } void DynamicAutomationPeer::Toggle() const { @@ -245,18 +234,9 @@ void DynamicAutomationPeer::Toggle() const { // IExpandCollapseProvider winrt::ExpandCollapseState DynamicAutomationPeer::ExpandCollapseState() const { - bool expandedState = GetAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Expanded); - bool collapsedState = GetAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates::Collapsed); - - if (!expandedState && collapsedState) { - return winrt::ExpandCollapseState::Collapsed; - } else if (expandedState && !collapsedState) { - return winrt::ExpandCollapseState::Expanded; - } else if (expandedState && collapsedState) { - return winrt::ExpandCollapseState::PartiallyExpanded; - } + bool expandedState = DynamicAutomationProperties::GetAccessibilityStateExpanded(Owner()); - return winrt::ExpandCollapseState::LeafNode; + return expandedState ? winrt::ExpandCollapseState::Expanded : winrt::ExpandCollapseState::Collapsed; } void DynamicAutomationPeer::Expand() const { @@ -353,18 +333,12 @@ bool DynamicAutomationPeer::HasAccessibilityState(winrt::Microsoft::ReactNative: case winrt::Microsoft::ReactNative::AccessibilityStates::Checked: value = owner.ReadLocalValue(DynamicAutomationProperties::AccessibilityStateCheckedProperty()); break; - case winrt::Microsoft::ReactNative::AccessibilityStates::Unchecked: - value = owner.ReadLocalValue(DynamicAutomationProperties::AccessibilityStateUncheckedProperty()); - break; case winrt::Microsoft::ReactNative::AccessibilityStates::Busy: value = owner.ReadLocalValue(DynamicAutomationProperties::AccessibilityStateBusyProperty()); break; case winrt::Microsoft::ReactNative::AccessibilityStates::Expanded: value = owner.ReadLocalValue(DynamicAutomationProperties::AccessibilityStateExpandedProperty()); break; - case winrt::Microsoft::ReactNative::AccessibilityStates::Collapsed: - value = owner.ReadLocalValue(DynamicAutomationProperties::AccessibilityStateCollapsedProperty()); - break; } return (value != xaml::DependencyProperty::UnsetValue()); } catch (...) { @@ -373,31 +347,6 @@ bool DynamicAutomationPeer::HasAccessibilityState(winrt::Microsoft::ReactNative: return false; } -bool DynamicAutomationPeer::GetAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates state) const { - try { - auto const &owner = Owner(); - switch (state) { - case winrt::Microsoft::ReactNative::AccessibilityStates::Selected: - return DynamicAutomationProperties::GetAccessibilityStateSelected(owner); - case winrt::Microsoft::ReactNative::AccessibilityStates::Disabled: - return DynamicAutomationProperties::GetAccessibilityStateDisabled(owner); - case winrt::Microsoft::ReactNative::AccessibilityStates::Checked: - return DynamicAutomationProperties::GetAccessibilityStateChecked(owner); - case winrt::Microsoft::ReactNative::AccessibilityStates::Unchecked: - return DynamicAutomationProperties::GetAccessibilityStateUnchecked(owner); - case winrt::Microsoft::ReactNative::AccessibilityStates::Busy: - return DynamicAutomationProperties::GetAccessibilityStateBusy(owner); - case winrt::Microsoft::ReactNative::AccessibilityStates::Expanded: - return DynamicAutomationProperties::GetAccessibilityStateExpanded(owner); - case winrt::Microsoft::ReactNative::AccessibilityStates::Collapsed: - return DynamicAutomationProperties::GetAccessibilityStateCollapsed(owner); - } - } catch (...) { - } - - return false; -} - bool DynamicAutomationPeer::HasAccessibilityValue(winrt::Microsoft::ReactNative::AccessibilityValue accValue) const { try { auto const &owner = Owner(); diff --git a/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.h b/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.h index e688749d4a0..eabe96e5a43 100644 --- a/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.h +++ b/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.h @@ -73,7 +73,6 @@ struct DynamicAutomationPeer : DynamicAutomationPeerT { winrt::hstring GetContentName() const; winrt::Microsoft::ReactNative::AccessibilityRoles GetAccessibilityRole() const; bool HasAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates state) const; - bool GetAccessibilityState(winrt::Microsoft::ReactNative::AccessibilityStates state) const; bool HasAccessibilityValue(winrt::Microsoft::ReactNative::AccessibilityValue value) const; double GetAccessibilityValueRange(winrt::Microsoft::ReactNative::AccessibilityValue value) const; diff --git a/vnext/Microsoft.ReactNative/Views/DynamicAutomationProperties.cpp b/vnext/Microsoft.ReactNative/Views/DynamicAutomationProperties.cpp index ea74dc035da..7016a1d43f4 100644 --- a/vnext/Microsoft.ReactNative/Views/DynamicAutomationProperties.cpp +++ b/vnext/Microsoft.ReactNative/Views/DynamicAutomationProperties.cpp @@ -87,37 +87,22 @@ bool DynamicAutomationProperties::GetAccessibilityStateDisabled(xaml::UIElement xaml::DependencyProperty DynamicAutomationProperties::AccessibilityStateCheckedProperty() { static xaml::DependencyProperty s_AccessibilityStateCheckedProperty = xaml::DependencyProperty::RegisterAttached( L"AccessibilityStateChecked", - winrt::xaml_typename(), + winrt::xaml_typename(), dynamicAutomationTypeName, - winrt::PropertyMetadata(winrt::box_value(false))); + winrt::PropertyMetadata(winrt::box_value(AccessibilityStateCheckedValue::Unchecked))); return s_AccessibilityStateCheckedProperty; } -void DynamicAutomationProperties::SetAccessibilityStateChecked(xaml::UIElement const &element, bool value) { - element.SetValue(AccessibilityStateCheckedProperty(), winrt::box_value(value)); -} - -bool DynamicAutomationProperties::GetAccessibilityStateChecked(xaml::UIElement const &element) { - return winrt::unbox_value(element.GetValue(AccessibilityStateCheckedProperty())); -} - -xaml::DependencyProperty DynamicAutomationProperties::AccessibilityStateUncheckedProperty() { - static xaml::DependencyProperty s_AccessibilityStateUncheckedProperty = xaml::DependencyProperty::RegisterAttached( - L"AccessibilityStateUnchecked", - winrt::xaml_typename(), - dynamicAutomationTypeName, - winrt::PropertyMetadata(winrt::box_value(false))); - - return s_AccessibilityStateUncheckedProperty; -} - -void DynamicAutomationProperties::SetAccessibilityStateUnchecked(xaml::UIElement const &element, bool value) { - element.SetValue(AccessibilityStateUncheckedProperty(), winrt::box_value(value)); +void DynamicAutomationProperties::SetAccessibilityStateChecked( + xaml::UIElement const &element, + AccessibilityStateCheckedValue value) { + element.SetValue(AccessibilityStateCheckedProperty(), winrt::box_value(value)); } -bool DynamicAutomationProperties::GetAccessibilityStateUnchecked(xaml::UIElement const &element) { - return winrt::unbox_value(element.GetValue(AccessibilityStateUncheckedProperty())); +AccessibilityStateCheckedValue DynamicAutomationProperties::GetAccessibilityStateChecked( + xaml::UIElement const &element) { + return winrt::unbox_value(element.GetValue(AccessibilityStateCheckedProperty())); } xaml::DependencyProperty DynamicAutomationProperties::AccessibilityStateBusyProperty() { @@ -156,24 +141,6 @@ bool DynamicAutomationProperties::GetAccessibilityStateExpanded(xaml::UIElement return winrt::unbox_value(element.GetValue(AccessibilityStateExpandedProperty())); } -xaml::DependencyProperty DynamicAutomationProperties::AccessibilityStateCollapsedProperty() { - static xaml::DependencyProperty s_AccessibilityStateCollapsedProperty = xaml::DependencyProperty::RegisterAttached( - L"AccessibilityStateCollapsed", - winrt::xaml_typename(), - dynamicAutomationTypeName, - winrt::PropertyMetadata(winrt::box_value(false))); - - return s_AccessibilityStateCollapsedProperty; -} - -void DynamicAutomationProperties::SetAccessibilityStateCollapsed(xaml::UIElement const &element, bool value) { - element.SetValue(AccessibilityStateCollapsedProperty(), winrt::box_value(value)); -} - -bool DynamicAutomationProperties::GetAccessibilityStateCollapsed(xaml::UIElement const &element) { - return winrt::unbox_value(element.GetValue(AccessibilityStateCollapsedProperty())); -} - xaml::DependencyProperty DynamicAutomationProperties::AccessibilityValueMinProperty() { static xaml::DependencyProperty s_AccessibilityValueMinProperty = xaml::DependencyProperty::RegisterAttached( L"AccessibilityValueMin", diff --git a/vnext/Microsoft.ReactNative/Views/DynamicAutomationProperties.h b/vnext/Microsoft.ReactNative/Views/DynamicAutomationProperties.h index c037c2cdb0a..b38bf24cf03 100644 --- a/vnext/Microsoft.ReactNative/Views/DynamicAutomationProperties.h +++ b/vnext/Microsoft.ReactNative/Views/DynamicAutomationProperties.h @@ -35,12 +35,8 @@ struct DynamicAutomationProperties : DynamicAutomationPropertiesT(winrt::Microsoft::ReactNative::AccessibilityStates::CountStates)] = {}; - if (propertyValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Object) { for (const auto &pair : propertyValue.AsObject()) { + // States are provided with the name and either a valid value if the state is supported or null if the state + // isn't const std::string &innerName = pair.first; const auto &innerValue = pair.second; - auto peer = xaml::Automation::Peers::FrameworkElementAutomationPeer::FromElement(element); + xaml::DependencyProperty targetDP = nullptr; + xaml::Automation::AutomationProperty targetAP = nullptr; + + bool valueChanged = false; + + winrt::IInspectable oldDPValue = xaml::DependencyProperty::UnsetValue(); + winrt::IInspectable newDPValue = xaml::DependencyProperty::UnsetValue(); + winrt::IInspectable oldAPValue = nullptr; + winrt::IInspectable newAPValue = nullptr; + + // Determine which attached dependency property to update and which automation property to raise a changed + // event if (innerName == "selected") { - states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Selected)] = - innerValue.AsBoolean(); - const auto prevSelectedState = DynamicAutomationProperties::GetAccessibilityStateSelected(element); - if (peer != nullptr && prevSelectedState != innerValue.AsBoolean()) { - peer.RaisePropertyChangedEvent( - winrt::SelectionItemPatternIdentifiers::IsSelectedProperty(), - winrt::box_value(prevSelectedState), - winrt::box_value(innerValue.AsBoolean())); - } + targetDP = DynamicAutomationProperties::AccessibilityStateSelectedProperty(); + targetAP = winrt::SelectionItemPatternIdentifiers::IsSelectedProperty(); } else if (innerName == "disabled") { - states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Disabled)] = - innerValue.AsBoolean(); - const auto prevDisabledState = DynamicAutomationProperties::GetAccessibilityStateDisabled(element); - - if (peer != nullptr && prevDisabledState != innerValue.AsBoolean()) { - peer.RaisePropertyChangedEvent( - winrt::AutomationElementIdentifiers::IsEnabledProperty(), - winrt::box_value(!prevDisabledState), - winrt::box_value(!innerValue.AsBoolean())); - } + targetDP = DynamicAutomationProperties::AccessibilityStateDisabledProperty(); + targetAP = winrt::AutomationElementIdentifiers::IsEnabledProperty(); } else if (innerName == "checked") { - states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Checked)] = - innerValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Boolean && innerValue.AsBoolean(); - states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Unchecked)] = - innerValue.Type() == winrt::Microsoft::ReactNative::JSValueType::Boolean && !innerValue.AsBoolean(); - // If the state is "mixed" we'll just set both Checked and Unchecked to false, - // then later in the IToggleProvider implementation it will return the Intermediate state - // due to both being set to false (see DynamicAutomationPeer::ToggleState()). - const auto prevCheckedState = DynamicAutomationProperties::GetAccessibilityStateChecked(element); - const auto prevUncheckedState = DynamicAutomationProperties::GetAccessibilityStateUnchecked(element); - - if (peer != nullptr) { - if (prevCheckedState != - states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Checked)] || - prevUncheckedState != - states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Unchecked)]) { - // Checking if either state has changed here to catch changes involving "mixed" state. - const auto oldValue = prevCheckedState ? winrt::ToggleState::On : winrt::ToggleState::Off; - if (innerValue.Type() != winrt::Microsoft::ReactNative::JSValueType::Boolean) { - peer.RaisePropertyChangedEvent( - winrt::TogglePatternIdentifiers::ToggleStateProperty(), - winrt::box_value(oldValue), - winrt::box_value(winrt::ToggleState::Indeterminate)); - } else { - const auto newValue = innerValue.AsBoolean() ? winrt::ToggleState::On : winrt::ToggleState::Off; - peer.RaisePropertyChangedEvent( - winrt::TogglePatternIdentifiers::ToggleStateProperty(), - winrt::box_value(oldValue), - winrt::box_value(newValue)); - } + targetDP = DynamicAutomationProperties::AccessibilityStateCheckedProperty(); + targetAP = winrt::TogglePatternIdentifiers::ToggleStateProperty(); + } else if (innerName == "busy") { + targetDP = DynamicAutomationProperties::AccessibilityStateBusyProperty(); + targetAP = winrt::AutomationElementIdentifiers::ItemStatusProperty(); + } else if (innerName == "expanded") { + targetDP = DynamicAutomationProperties::AccessibilityStateExpandedProperty(); + targetAP = winrt::ExpandCollapsePatternIdentifiers::ExpandCollapseStateProperty(); + } + + if (targetDP != nullptr) { + // Determine values for DP and AP + + oldDPValue = element.ReadLocalValue(targetDP); + + const bool hasOldValue = oldDPValue != xaml::DependencyProperty::UnsetValue(); + + if (innerName == "checked") { + // Checked is special and can support null, boolean true, boolean false, or the string "mixed" + + auto oldValue = hasOldValue + ? winrt::unbox_value(oldDPValue) + : winrt::Microsoft::ReactNative::AccessibilityStateCheckedValue::Unchecked; + + winrt::Microsoft::ReactNative::AccessibilityStateCheckedValue newValue = + winrt::Microsoft::ReactNative::AccessibilityStateCheckedValue::Unchecked; + + const auto pRawBooleanNewValue = innerValue.TryGetBoolean(); + const auto pRawStringNewValue = innerValue.TryGetString(); + + if (pRawBooleanNewValue != nullptr) { + // State value is a valid boolean + newValue = *pRawBooleanNewValue + ? winrt::Microsoft::ReactNative::AccessibilityStateCheckedValue::Checked + : winrt::Microsoft::ReactNative::AccessibilityStateCheckedValue::Unchecked; + newDPValue = winrt::box_value(newValue); + valueChanged = !hasOldValue || (oldValue != newValue); // Value was unset before or set but different + } else if (pRawStringNewValue != nullptr && *pRawStringNewValue == "mixed") { + // State value is the valid string "mixed" + newValue = winrt::Microsoft::ReactNative::AccessibilityStateCheckedValue::Mixed; + newDPValue = winrt::box_value(newValue); + valueChanged = !hasOldValue || (oldValue != newValue); // Value was unset before or set but different + } else { + // State value is null or not valid + valueChanged = hasOldValue; // Value was set before + } + + oldAPValue = + winrt::box_value(hasOldValue ? static_cast(oldValue) : winrt::ToggleState::Off); + newAPValue = winrt::box_value(static_cast(newValue)); + } else { + // All other accessibility state values support null, boolean true or boolean false + + auto oldValue = hasOldValue ? winrt::unbox_value(oldDPValue) : false; + + const bool *pNewValue = innerValue.TryGetBoolean(); + + if (pNewValue != nullptr) { + // State value is a valid boolean + newDPValue = winrt::box_value(*pNewValue); + valueChanged = !hasOldValue || (oldValue != *pNewValue); // Value was unset before or set but different + } else { + // State value is null or not valid + valueChanged = hasOldValue; // Value was set before + } + + if (innerName == "disabled") { + // Disabled maps to enabled, flip boolean + oldAPValue = winrt::box_value(!(hasOldValue ? oldValue : false)); + newAPValue = winrt::box_value(!(pNewValue != nullptr ? *pNewValue : false)); + } else if (innerName == "busy") { + oldAPValue = winrt::box_value(hasOldValue && oldValue ? L"Busy" : L""); + newAPValue = winrt::box_value(pNewValue != nullptr && *pNewValue ? L"Busy" : L""); + } else if (innerName == "expanded") { + oldAPValue = winrt::box_value( + hasOldValue && oldValue ? winrt::ExpandCollapseState::Expanded + : winrt::ExpandCollapseState::Collapsed); + newAPValue = winrt::box_value( + pNewValue != nullptr && *pNewValue ? winrt::ExpandCollapseState::Expanded + : winrt::ExpandCollapseState::Collapsed); + } else { + // Direct mapping of boolean + oldAPValue = winrt::box_value(hasOldValue ? oldValue : false); + newAPValue = winrt::box_value(pNewValue != nullptr ? *pNewValue : false); } } - } else if (innerName == "busy") - states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Busy)] = - !innerValue.IsNull() && innerValue.AsBoolean(); - else if (innerName == "expanded") { - states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Expanded)] = - !innerValue.IsNull() && innerValue.AsBoolean(); - states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Collapsed)] = - innerValue.IsNull() ? false : !innerValue.AsBoolean(); - - const auto prevExpandedState = DynamicAutomationProperties::GetAccessibilityStateExpanded(element); - - if (peer != nullptr && prevExpandedState != innerValue.AsBoolean()) { - const auto newValue = - innerValue.AsBoolean() ? winrt::ExpandCollapseState::Expanded : winrt::ExpandCollapseState::Collapsed; - const auto oldValue = - prevExpandedState ? winrt::ExpandCollapseState::Expanded : winrt::ExpandCollapseState::Collapsed; - peer.RaisePropertyChangedEvent( - winrt::ExpandCollapsePatternIdentifiers::ExpandCollapseStateProperty(), - winrt::box_value(oldValue), - winrt::box_value(newValue)); + + // Update attached dependency property for element + if (newDPValue != xaml::DependencyProperty::UnsetValue()) { + // State value was valid, so set + element.SetValue(targetDP, newDPValue); + } else { + // State value is null or not valid, so clear + element.ClearValue(targetDP); + } + + // Raise automation property changed event if the value changed + if (valueChanged && targetAP != nullptr && oldAPValue != nullptr && newAPValue != nullptr) { + if (auto peer = xaml::Automation::Peers::FrameworkElementAutomationPeer::FromElement(element)) { + peer.RaisePropertyChangedEvent(targetAP, oldAPValue, newAPValue); + } } } } } - - DynamicAutomationProperties::SetAccessibilityStateSelected( - element, states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Selected)]); - DynamicAutomationProperties::SetAccessibilityStateDisabled( - element, states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Disabled)]); - DynamicAutomationProperties::SetAccessibilityStateChecked( - element, states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Checked)]); - DynamicAutomationProperties::SetAccessibilityStateUnchecked( - element, states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Unchecked)]); - DynamicAutomationProperties::SetAccessibilityStateBusy( - element, states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Busy)]); - DynamicAutomationProperties::SetAccessibilityStateExpanded( - element, states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Expanded)]); - DynamicAutomationProperties::SetAccessibilityStateCollapsed( - element, states[static_cast(winrt::Microsoft::ReactNative::AccessibilityStates::Collapsed)]); } else if (propertyName == "accessibilityValue") { winrt::hstring textValue; const int numericValuesCount = 3; diff --git a/vnext/Microsoft.ReactNative/Views/cppwinrt/DynamicAutomationPeer.idl b/vnext/Microsoft.ReactNative/Views/cppwinrt/DynamicAutomationPeer.idl index 7d3162f4302..a65d9cd76b9 100644 --- a/vnext/Microsoft.ReactNative/Views/cppwinrt/DynamicAutomationPeer.idl +++ b/vnext/Microsoft.ReactNative/Views/cppwinrt/DynamicAutomationPeer.idl @@ -49,13 +49,18 @@ namespace Microsoft.ReactNative Selected = 0, Disabled, Checked, - Unchecked, Busy, Expanded, - Collapsed, CountStates }; + enum AccessibilityStateCheckedValue + { + Unchecked = 0, // Maps to ToggleState::Off + Checked, // Maps to ToggleState::On + Mixed // Maps to ToggleState::Indeterminate + }; + // When adding a new numeric value, make sure to increment 'numericValuesCount' in FrameworkElementViewManager // updateProperties depends on Min, Max, Now values being 0-2 for indexing. Be careful not to break that logic when adding new values. enum AccessibilityValue @@ -87,12 +92,8 @@ namespace Microsoft.ReactNative static Boolean GetAccessibilityStateDisabled(XAML_NAMESPACE.UIElement element); static XAML_NAMESPACE.DependencyProperty AccessibilityStateCheckedProperty { get; }; - static void SetAccessibilityStateChecked(XAML_NAMESPACE.UIElement element, Boolean value); - static Boolean GetAccessibilityStateChecked(XAML_NAMESPACE.UIElement element); - - static XAML_NAMESPACE.DependencyProperty AccessibilityStateUncheckedProperty { get; }; - static void SetAccessibilityStateUnchecked(XAML_NAMESPACE.UIElement element, Boolean value); - static Boolean GetAccessibilityStateUnchecked(XAML_NAMESPACE.UIElement element); + static void SetAccessibilityStateChecked(XAML_NAMESPACE.UIElement element, AccessibilityStateCheckedValue value); + static AccessibilityStateCheckedValue GetAccessibilityStateChecked(XAML_NAMESPACE.UIElement element); static XAML_NAMESPACE.DependencyProperty AccessibilityStateBusyProperty { get; }; static void SetAccessibilityStateBusy(XAML_NAMESPACE.UIElement element, Boolean value); @@ -102,10 +103,6 @@ namespace Microsoft.ReactNative static void SetAccessibilityStateExpanded(XAML_NAMESPACE.UIElement element, Boolean value); static Boolean GetAccessibilityStateExpanded(XAML_NAMESPACE.UIElement element); - static XAML_NAMESPACE.DependencyProperty AccessibilityStateCollapsedProperty { get; }; - static void SetAccessibilityStateCollapsed(XAML_NAMESPACE.UIElement element, Boolean value); - static Boolean GetAccessibilityStateCollapsed(XAML_NAMESPACE.UIElement element); - static XAML_NAMESPACE.DependencyProperty AccessibilityValueMinProperty { get; }; static void SetAccessibilityValueMin(XAML_NAMESPACE.UIElement element, Double value); static Double GetAccessibilityValueMin(XAML_NAMESPACE.UIElement element); From 92457d360f4b3765f2a386587aeedfbd830d78d2 Mon Sep 17 00:00:00 2001 From: "Jon Thysell (JAUNTY)" Date: Tue, 20 Jun 2023 17:12:11 -0700 Subject: [PATCH 2/9] Change files --- ...ative-windows-d269038a-a1db-4d00-a62c-ff552f06c42f.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/react-native-windows-d269038a-a1db-4d00-a62c-ff552f06c42f.json diff --git a/change/react-native-windows-d269038a-a1db-4d00-a62c-ff552f06c42f.json b/change/react-native-windows-d269038a-a1db-4d00-a62c-ff552f06c42f.json new file mode 100644 index 00000000000..d46106c6986 --- /dev/null +++ b/change/react-native-windows-d269038a-a1db-4d00-a62c-ff552f06c42f.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Fix accessibilityState to support states not being set", + "packageName": "react-native-windows", + "email": "jthysell@microsoft.com", + "dependentChangeType": "patch" +} From f457fd34dd1f72b7c632421bbd0b12ef3c442a4d Mon Sep 17 00:00:00 2001 From: "Jon Thysell (JAUNTY)" Date: Tue, 20 Jun 2023 17:21:40 -0700 Subject: [PATCH 3/9] add accessiblity states to xaml dump --- .../automation-commands/src/dumpVisualTree.ts | 6 ++++++ .../e2e-test-app/windows/RNTesterApp/MainPage.xaml.cs | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts b/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts index 51d01a7e003..924b9ce8d6d 100644 --- a/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts +++ b/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts @@ -118,6 +118,12 @@ function removeDefaultProps(element: UIElement) { ['AutomationLevel', -1], ['AutomationPositionInSet', -1], ['AutomationSizeOfSet', -1], + ['AccessibilityRole', null], + ['AccessibilityStateSelected', null], + ['AccessibilityStateDisabled', null], + ['AccessibilityStateChecked', null], + ['AccessibilityStateBusy', null], + ['AccessibilityStateExpanded', null], ]; defaultValues.forEach(([propname, defaultValue]) => { diff --git a/packages/e2e-test-app/windows/RNTesterApp/MainPage.xaml.cs b/packages/e2e-test-app/windows/RNTesterApp/MainPage.xaml.cs index 3e4350faf32..82cc1001da6 100644 --- a/packages/e2e-test-app/windows/RNTesterApp/MainPage.xaml.cs +++ b/packages/e2e-test-app/windows/RNTesterApp/MainPage.xaml.cs @@ -78,6 +78,12 @@ JsonObject DumpVisualTree(JsonValue payload) new AttachedProperty() { Name = "AutomationLevel", Property = Windows.UI.Xaml.Automation.AutomationProperties.LevelProperty }, new AttachedProperty() { Name = "AutomationSizeOfSet", Property = Windows.UI.Xaml.Automation.AutomationProperties.SizeOfSetProperty }, new AttachedProperty() { Name = "AutomationPositionInSet", Property = Windows.UI.Xaml.Automation.AutomationProperties.PositionInSetProperty }, + new AttachedProperty() { Name = "AccessibilityRole", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityRoleProperty }, + new AttachedProperty() { Name = "AccessibilityStateSelected", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateSelectedProperty }, + new AttachedProperty() { Name = "AccessibilityStateDisabled", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateDisabledProperty }, + new AttachedProperty() { Name = "AccessibilityStateChecked", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateCheckedProperty }, + new AttachedProperty() { Name = "AccessibilityStateBusy", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateBusyProperty }, + new AttachedProperty() { Name = "AccessibilityStateExpanded", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateExpandedProperty }, }; var rootDump = VisualTreeDumper.DumpTree(this, null, additionalProperties, attachedProperties); var element = VisualTreeDumper.FindElementByAutomationId(JsonObject.Parse(rootDump), accessibilityId); @@ -115,7 +121,8 @@ async Task LoopServer(Server server) try { await server.ProcessAllClientRequests(8603, TimeSpan.FromMilliseconds(50)); - } catch( Exception ex) + } + catch (Exception ex) { } } From 71fc7bdce87dd210241503a743c2d51c5cf3e8ac Mon Sep 17 00:00:00 2001 From: "Jon Thysell (JAUNTY)" Date: Wed, 21 Jun 2023 13:45:50 -0700 Subject: [PATCH 4/9] Change files --- ...tion-commands-bd4c0b18-0390-4f53-b491-1c7671344cd2.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@react-native-windows-automation-commands-bd4c0b18-0390-4f53-b491-1c7671344cd2.json diff --git a/change/@react-native-windows-automation-commands-bd4c0b18-0390-4f53-b491-1c7671344cd2.json b/change/@react-native-windows-automation-commands-bd4c0b18-0390-4f53-b491-1c7671344cd2.json new file mode 100644 index 00000000000..34f174a1050 --- /dev/null +++ b/change/@react-native-windows-automation-commands-bd4c0b18-0390-4f53-b491-1c7671344cd2.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Fix accessibilityState to support states not being set", + "packageName": "@react-native-windows/automation-commands", + "email": "jthysell@microsoft.com", + "dependentChangeType": "patch" +} From 73633cebacbccd0631cb2b0d8836fb4a6872c100 Mon Sep 17 00:00:00 2001 From: "Jon Thysell (JAUNTY)" Date: Thu, 22 Jun 2023 12:22:15 -0700 Subject: [PATCH 5/9] fix crashes --- package.json | 2 + .../automation-commands/src/dumpVisualTree.ts | 12 +-- .../windows/RNTesterApp/MainPage.xaml.cs | 1 + .../windows/RNTesterApp/packages.lock.json | 40 +++++++--- .../packages.lock.json | 73 ++++++++++++++++++- .../Views/DynamicAutomationPeer.cpp | 39 ++++++++-- yarn.lock | 16 +--- 7 files changed, 142 insertions(+), 41 deletions(-) diff --git a/package.json b/package.json index 80482e5b9b5..d7fdddcf9df 100644 --- a/package.json +++ b/package.json @@ -47,9 +47,11 @@ "lodash": "^4.17.15" }, "resolutions": { + "convert-source-map": "^2.0.0", "kind-of": "6.0.3", "glob-parent": "^5.1.2", "node-notifier": "^9.0.0", + "safe-buffer": "^5.2.1", "set-value": "^4.0.1", "strip-ansi": "^6.0.1", "**/parse-url/normalize-url": "^4.5.1", diff --git a/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts b/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts index 924b9ce8d6d..1beda9925ed 100644 --- a/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts +++ b/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts @@ -118,12 +118,12 @@ function removeDefaultProps(element: UIElement) { ['AutomationLevel', -1], ['AutomationPositionInSet', -1], ['AutomationSizeOfSet', -1], - ['AccessibilityRole', null], - ['AccessibilityStateSelected', null], - ['AccessibilityStateDisabled', null], - ['AccessibilityStateChecked', null], - ['AccessibilityStateBusy', null], - ['AccessibilityStateExpanded', null], + ['AccessibilityRole', 'Unknown'], + ['AccessibilityStateSelected', false], + ['AccessibilityStateDisabled', false], + ['AccessibilityStateChecked', false], + ['AccessibilityStateBusy', false], + ['AccessibilityStateExpanded', false], ]; defaultValues.forEach(([propname, defaultValue]) => { diff --git a/packages/e2e-test-app/windows/RNTesterApp/MainPage.xaml.cs b/packages/e2e-test-app/windows/RNTesterApp/MainPage.xaml.cs index 82cc1001da6..07d11ccfe40 100644 --- a/packages/e2e-test-app/windows/RNTesterApp/MainPage.xaml.cs +++ b/packages/e2e-test-app/windows/RNTesterApp/MainPage.xaml.cs @@ -86,6 +86,7 @@ JsonObject DumpVisualTree(JsonValue payload) new AttachedProperty() { Name = "AccessibilityStateExpanded", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateExpandedProperty }, }; var rootDump = VisualTreeDumper.DumpTree(this, null, additionalProperties, attachedProperties); + rootDump = rootDump.Replace(" False", " false").Replace(" True", " true"); // Temporary workaround until we can fix upstream to produce correct JSON boolean values var element = VisualTreeDumper.FindElementByAutomationId(JsonObject.Parse(rootDump), accessibilityId); if (element != null) return element; diff --git a/packages/e2e-test-app/windows/RNTesterApp/packages.lock.json b/packages/e2e-test-app/windows/RNTesterApp/packages.lock.json index 623c4918f3e..a31212e0e21 100644 --- a/packages/e2e-test-app/windows/RNTesterApp/packages.lock.json +++ b/packages/e2e-test-app/windows/RNTesterApp/packages.lock.json @@ -2,12 +2,6 @@ "version": 1, "dependencies": { "UAP,Version=v10.0.17763": { - "Microsoft.JavaScript.Hermes": { - "type": "Direct", - "requested": "[0.1.14, )", - "resolved": "0.1.14", - "contentHash": "YhW4fHxZ+ZIt3eZbFiMxhBzkZPISudZx9rEX+4RlB5EZWzpaKUAqfSUQJcapqdPXa4bw4dla9q9THyUqveBBRA==" - }, "Microsoft.NETCore.UniversalWindowsPlatform": { "type": "Direct", "requested": "[6.2.9, )", @@ -35,6 +29,16 @@ "resolved": "1.0.9", "contentHash": "rvh/RZghhSG28PDL1dw56nTZRN0/ViV2TIja/ykU9FHn0gtM8pwtgD8Ebo1nobu0QnSjn8Cg6Ncu39VV19rkrw==" }, + "boost": { + "type": "Transitive", + "resolved": "1.76.0", + "contentHash": "p+w3YvNdXL8Cu9Fzrmexssu0tZbWxuf6ywsQqHjDlKFE5ojXHof1HIyMC3zDLfLnh80dIeFcEUAuR2Asg/XHRA==" + }, + "Microsoft.JavaScript.Hermes": { + "type": "Transitive", + "resolved": "0.1.15", + "contentHash": "My/u5RvxoymtwWokoweU6iVpuP79w271UjadcmSNqnQ9ESIv00tlVP4sHnIiN3t2lJNDeciyE1EVF4swGPECKQ==" + }, "Microsoft.Net.Native.Compiler": { "type": "Transitive", "resolved": "2.2.7-rel-27913-00", @@ -66,6 +70,11 @@ "resolved": "1.0.1264.42", "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" }, + "Microsoft.Windows.SDK.BuildTools": { + "type": "Transitive", + "resolved": "10.0.22000.194", + "contentHash": "4L0P3zqut466SIqT3VBeLTNUQTxCBDOrTRymRuROCRJKazcK7ibLz9yAO1nKWRt50ttCj39oAa2Iuz9ZTDmLlg==" + }, "NETStandard.Library": { "type": "Transitive", "resolved": "2.0.3", @@ -144,7 +153,8 @@ "automationchannel": { "type": "Project", "dependencies": { - "Microsoft.ReactNative": "[1.0.0, )" + "Microsoft.ReactNative": "[1.0.0, )", + "Microsoft.UI.Xaml": "[2.8.0, )" } }, "common": { @@ -156,6 +166,7 @@ "folly": { "type": "Project", "dependencies": { + "boost": "[1.76.0, )", "fmt": "[1.0.0, )" } }, @@ -164,7 +175,11 @@ "dependencies": { "Common": "[1.0.0, )", "Folly": "[1.0.0, )", - "ReactCommon": "[1.0.0, )" + "Microsoft.JavaScript.Hermes": "[0.1.15, )", + "Microsoft.UI.Xaml": "[2.8.0, )", + "Microsoft.Windows.SDK.BuildTools": "[10.0.22000.194, )", + "ReactCommon": "[1.0.0, )", + "boost": "[1.76.0, )" } }, "microsoft.reactnative.managed": { @@ -177,19 +192,22 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )" + "Folly": "[1.0.0, )", + "boost": "[1.76.0, )" } }, "reactnativepicker": { "type": "Project", "dependencies": { - "Microsoft.ReactNative": "[1.0.0, )" + "Microsoft.ReactNative": "[1.0.0, )", + "Microsoft.UI.Xaml": "[2.8.0, )" } }, "reactnativexaml": { "type": "Project", "dependencies": { - "Microsoft.ReactNative": "[1.0.0, )" + "Microsoft.ReactNative": "[1.0.0, )", + "Microsoft.UI.Xaml": "[2.8.0, )" } } }, diff --git a/vnext/Microsoft.ReactNative.Managed/packages.lock.json b/vnext/Microsoft.ReactNative.Managed/packages.lock.json index 2750d3ec05d..6f57327d8b9 100644 --- a/vnext/Microsoft.ReactNative.Managed/packages.lock.json +++ b/vnext/Microsoft.ReactNative.Managed/packages.lock.json @@ -24,11 +24,21 @@ "Microsoft.SourceLink.Common": "1.0.0" } }, + "boost": { + "type": "Transitive", + "resolved": "1.76.0", + "contentHash": "p+w3YvNdXL8Cu9Fzrmexssu0tZbWxuf6ywsQqHjDlKFE5ojXHof1HIyMC3zDLfLnh80dIeFcEUAuR2Asg/XHRA==" + }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "1.0.0", "contentHash": "z2fpmmt+1Jfl+ZnBki9nSP08S1/tbEOxFdsK1rSR+LBehIJz1Xv9/6qOOoGNqlwnAGGVGis1Oj6S8Kt9COEYlQ==" }, + "Microsoft.JavaScript.Hermes": { + "type": "Transitive", + "resolved": "0.1.15", + "contentHash": "My/u5RvxoymtwWokoweU6iVpuP79w271UjadcmSNqnQ9ESIv00tlVP4sHnIiN3t2lJNDeciyE1EVF4swGPECKQ==" + }, "Microsoft.Net.Native.Compiler": { "type": "Transitive", "resolved": "2.2.7-rel-27913-00", @@ -60,6 +70,24 @@ "resolved": "1.0.0", "contentHash": "G8DuQY8/DK5NN+3jm5wcMcd9QYD90UV7MiLmdljSJixi3U/vNaeBKmmXUqI4DJCOeWizIUEh4ALhSt58mR+5eg==" }, + "Microsoft.UI.Xaml": { + "type": "Transitive", + "resolved": "2.8.0", + "contentHash": "vxdHxTr63s5KVtNddMFpgvjBjUH50z7seq/5jLWmmSuf8poxg+sXrywkofUdE8ZstbpO9y3FL/IXXUcPYbeesA==", + "dependencies": { + "Microsoft.Web.WebView2": "1.0.1264.42" + } + }, + "Microsoft.Web.WebView2": { + "type": "Transitive", + "resolved": "1.0.1264.42", + "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" + }, + "Microsoft.Windows.SDK.BuildTools": { + "type": "Transitive", + "resolved": "10.0.22000.194", + "contentHash": "4L0P3zqut466SIqT3VBeLTNUQTxCBDOrTRymRuROCRJKazcK7ibLz9yAO1nKWRt50ttCj39oAa2Iuz9ZTDmLlg==" + }, "NETStandard.Library": { "type": "Transitive", "resolved": "2.0.3", @@ -144,6 +172,7 @@ "folly": { "type": "Project", "dependencies": { + "boost": "[1.76.0, )", "fmt": "[1.0.0, )" } }, @@ -152,13 +181,18 @@ "dependencies": { "Common": "[1.0.0, )", "Folly": "[1.0.0, )", - "ReactCommon": "[1.0.0, )" + "Microsoft.JavaScript.Hermes": "[0.1.15, )", + "Microsoft.UI.Xaml": "[2.8.0, )", + "Microsoft.Windows.SDK.BuildTools": "[10.0.22000.194, )", + "ReactCommon": "[1.0.0, )", + "boost": "[1.76.0, )" } }, "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )" + "Folly": "[1.0.0, )", + "boost": "[1.76.0, )" } } }, @@ -176,6 +210,11 @@ "runtime.win10-arm.Microsoft.NETCore.UniversalWindowsPlatform": "6.2.9" } }, + "Microsoft.Web.WebView2": { + "type": "Transitive", + "resolved": "1.0.1264.42", + "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" + }, "runtime.win10-arm.Microsoft.NETCore.UniversalWindowsPlatform": { "type": "Transitive", "resolved": "6.2.9", @@ -196,6 +235,11 @@ "runtime.win10-arm-aot.Microsoft.NETCore.UniversalWindowsPlatform": "6.2.9" } }, + "Microsoft.Web.WebView2": { + "type": "Transitive", + "resolved": "1.0.1264.42", + "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" + }, "runtime.win10-arm-aot.Microsoft.NETCore.UniversalWindowsPlatform": { "type": "Transitive", "resolved": "6.2.9", @@ -216,6 +260,11 @@ "runtime.win10-arm64-aot.Microsoft.NETCore.UniversalWindowsPlatform": "6.2.9" } }, + "Microsoft.Web.WebView2": { + "type": "Transitive", + "resolved": "1.0.1264.42", + "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" + }, "runtime.win10-arm64-aot.Microsoft.NETCore.UniversalWindowsPlatform": { "type": "Transitive", "resolved": "6.2.9", @@ -236,6 +285,11 @@ "runtime.win10-x64.Microsoft.NETCore.UniversalWindowsPlatform": "6.2.9" } }, + "Microsoft.Web.WebView2": { + "type": "Transitive", + "resolved": "1.0.1264.42", + "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" + }, "runtime.win10-x64.Microsoft.NETCore.UniversalWindowsPlatform": { "type": "Transitive", "resolved": "6.2.9", @@ -256,6 +310,11 @@ "runtime.win10-x64-aot.Microsoft.NETCore.UniversalWindowsPlatform": "6.2.9" } }, + "Microsoft.Web.WebView2": { + "type": "Transitive", + "resolved": "1.0.1264.42", + "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" + }, "runtime.win10-x64-aot.Microsoft.NETCore.UniversalWindowsPlatform": { "type": "Transitive", "resolved": "6.2.9", @@ -276,6 +335,11 @@ "runtime.win10-x86.Microsoft.NETCore.UniversalWindowsPlatform": "6.2.9" } }, + "Microsoft.Web.WebView2": { + "type": "Transitive", + "resolved": "1.0.1264.42", + "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" + }, "runtime.win10-x86.Microsoft.NETCore.UniversalWindowsPlatform": { "type": "Transitive", "resolved": "6.2.9", @@ -296,6 +360,11 @@ "runtime.win10-x86-aot.Microsoft.NETCore.UniversalWindowsPlatform": "6.2.9" } }, + "Microsoft.Web.WebView2": { + "type": "Transitive", + "resolved": "1.0.1264.42", + "contentHash": "7OBUTkzQ5VI/3gb0ufi5U4zjuCowAJwQg2li0zXXzqkM+S1kmOlivTy1R4jAW+gY5Vyg510M+qMAESCQUjrfgA==" + }, "runtime.win10-x86-aot.Microsoft.NETCore.UniversalWindowsPlatform": { "type": "Transitive", "resolved": "6.2.9", diff --git a/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.cpp b/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.cpp index 0b20562805c..219615357ab 100644 --- a/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.cpp +++ b/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.cpp @@ -152,7 +152,11 @@ winrt::IInspectable DynamicAutomationPeer::GetPatternCore(winrt::PatternInterfac } bool DynamicAutomationPeer::IsEnabledCore() const { - bool disabled = DynamicAutomationProperties::GetAccessibilityStateDisabled(Owner()); + bool disabled = false; + try { + disabled = DynamicAutomationProperties::GetAccessibilityStateDisabled(Owner()); + } catch (...) { + } return !disabled && Super::IsEnabledCore(); } @@ -160,8 +164,11 @@ winrt::hstring DynamicAutomationPeer::GetItemStatusCore() const { winrt::hstring itemStatus = Super::GetItemStatusCore(); if (itemStatus.empty()) { - if (DynamicAutomationProperties::GetAccessibilityStateBusy(Owner())) { - itemStatus = L"Busy"; + try { + if (DynamicAutomationProperties::GetAccessibilityStateBusy(Owner())) { + itemStatus = L"Busy"; + } + } catch (...) { } } @@ -191,7 +198,12 @@ winrt::com_array DynamicAutomationPeer::GetSel // ISelectionItemProvider bool DynamicAutomationPeer::IsSelected() const { - return DynamicAutomationProperties::GetAccessibilityStateSelected(Owner()); + bool selected = false; + try { + return DynamicAutomationProperties::GetAccessibilityStateSelected(Owner()); + } catch (...) { + } + return false; } winrt::IRawElementProviderSimple DynamicAutomationPeer::SelectionContainer() const { @@ -218,9 +230,14 @@ void DynamicAutomationPeer::Select() const { // IToggleProvider winrt::ToggleState DynamicAutomationPeer::ToggleState() const { - auto checkedState = DynamicAutomationProperties::GetAccessibilityStateChecked(Owner()); + auto checkedState = winrt::ToggleState::Off; - return static_cast(checkedState); + try { + checkedState = static_cast(DynamicAutomationProperties::GetAccessibilityStateChecked(Owner())); + } catch (...) { + } + + return checkedState; } void DynamicAutomationPeer::Toggle() const { @@ -234,9 +251,15 @@ void DynamicAutomationPeer::Toggle() const { // IExpandCollapseProvider winrt::ExpandCollapseState DynamicAutomationPeer::ExpandCollapseState() const { - bool expandedState = DynamicAutomationProperties::GetAccessibilityStateExpanded(Owner()); + auto expandedState = winrt::ExpandCollapseState::Collapsed; - return expandedState ? winrt::ExpandCollapseState::Expanded : winrt::ExpandCollapseState::Collapsed; + try { + expandedState = DynamicAutomationProperties::GetAccessibilityStateExpanded(Owner()) + ? winrt::ExpandCollapseState::Expanded + : winrt::ExpandCollapseState::Collapsed; + } catch (...) { + } + return expandedState; } void DynamicAutomationPeer::Expand() const { diff --git a/yarn.lock b/yarn.lock index d5d4eb28380..19d75b30e78 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4695,14 +4695,7 @@ continuation-local-storage@^3.2.1: async-listener "^0.6.0" emitter-listener "^1.1.1" -convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" - -convert-source-map@^2.0.0: +convert-source-map@^1.6.0, convert-source-map@^1.7.0, convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== @@ -10920,12 +10913,7 @@ rxjs@^6.4.0, rxjs@^6.6.0: dependencies: tslib "^1.9.0" -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0: +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== From f52cdd106fd415abec0da54ef4bab2289a53757c Mon Sep 17 00:00:00 2001 From: "Jon Thysell (JAUNTY)" Date: Thu, 22 Jun 2023 14:25:02 -0700 Subject: [PATCH 6/9] fix unchecked default --- .../automation-commands/src/dumpVisualTree.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts b/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts index 1beda9925ed..318b8382434 100644 --- a/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts +++ b/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts @@ -121,7 +121,7 @@ function removeDefaultProps(element: UIElement) { ['AccessibilityRole', 'Unknown'], ['AccessibilityStateSelected', false], ['AccessibilityStateDisabled', false], - ['AccessibilityStateChecked', false], + ['AccessibilityStateChecked', 'Unchecked'], ['AccessibilityStateBusy', false], ['AccessibilityStateExpanded', false], ]; From b13673716b03312b518668f9c688306b9d8692ea Mon Sep 17 00:00:00 2001 From: "Jon Thysell (JAUNTY)" Date: Fri, 23 Jun 2023 11:18:05 -0700 Subject: [PATCH 7/9] Update to newer XamlDumpLibrary --- .../automation-commands/src/dumpVisualTree.ts | 13 +------ .../ButtonComponentTest.test.ts.snap | 14 ++++++++ .../FlyoutComponentTest.test.ts.snap | 3 ++ .../LegacyControlStyleTest.test.ts.snap | 3 ++ .../LegacyImageTest.test.ts.snap | 4 +++ .../PopupComponentTest.test.ts.snap | 3 ++ .../PressableComponentTest.test.ts.snap | 1 + .../ScrollViewComponentTest.test.ts.snap | 1 + .../SwitchComponentTest.test.ts.snap | 19 +++++++++-- .../ViewComponentTest.test.ts.snap | 1 + .../windows/RNTesterApp/MainPage.xaml.cs | 34 +++++++++++++------ .../windows/RNTesterApp/RNTesterApp.csproj | 2 +- .../windows/RNTesterApp/packages.lock.json | 6 ++-- 13 files changed, 75 insertions(+), 29 deletions(-) diff --git a/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts b/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts index 318b8382434..2335a2b5b67 100644 --- a/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts +++ b/packages/@react-native-windows/automation-commands/src/dumpVisualTree.ts @@ -113,18 +113,7 @@ function removeNonDeterministicProps(element: UIElement) { * Removes noise from snapshot by removing properties with the default value */ function removeDefaultProps(element: UIElement) { - const defaultValues: [string, unknown][] = [ - ['Tooltip', null], - ['AutomationLevel', -1], - ['AutomationPositionInSet', -1], - ['AutomationSizeOfSet', -1], - ['AccessibilityRole', 'Unknown'], - ['AccessibilityStateSelected', false], - ['AccessibilityStateDisabled', false], - ['AccessibilityStateChecked', 'Unchecked'], - ['AccessibilityStateBusy', false], - ['AccessibilityStateExpanded', false], - ]; + const defaultValues: [string, unknown][] = [['Tooltip', null]]; defaultValues.forEach(([propname, defaultValue]) => { if (element[propname] === defaultValue) { diff --git a/packages/e2e-test-app/test/__snapshots__/ButtonComponentTest.test.ts.snap b/packages/e2e-test-app/test/__snapshots__/ButtonComponentTest.test.ts.snap index e126e9fd521..449ded971f3 100644 --- a/packages/e2e-test-app/test/__snapshots__/ButtonComponentTest.test.ts.snap +++ b/packages/e2e-test-app/test/__snapshots__/ButtonComponentTest.test.ts.snap @@ -2,6 +2,8 @@ exports[`ButtonTests Buttons can be disabled 1`] = ` { + "AccessibilityRole": "Button", + "AccessibilityStateDisabled": true, "AutomationId": "disabled_button", "Background": null, "BorderBrush": null, @@ -93,6 +95,7 @@ exports[`ButtonTests Buttons can be disabled 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityStateDisabled": true, "Clip": null, "FlowDirection": "LeftToRight", "Foreground": "#5C000000", @@ -122,6 +125,7 @@ exports[`ButtonTests Buttons can be disabled 1`] = ` exports[`ButtonTests Buttons can have accessibility labels 1`] = ` { + "AccessibilityRole": "Button", "AutomationId": "accessibilityLabel_button", "Background": null, "BorderBrush": null, @@ -242,6 +246,7 @@ exports[`ButtonTests Buttons can have accessibility labels 1`] = ` exports[`ButtonTests Buttons can have accessibility props 1`] = ` { + "AccessibilityRole": "Button", "AutomationId": "accessibility_props", "Background": null, "BorderBrush": null, @@ -362,6 +367,8 @@ exports[`ButtonTests Buttons can have accessibility props 1`] = ` exports[`ButtonTests Buttons can have accessibility states 1`] = ` { + "AccessibilityRole": "Button", + "AccessibilityStateDisabled": true, "AutomationId": "accessibilityState_button", "Background": null, "BorderBrush": null, @@ -453,6 +460,7 @@ exports[`ButtonTests Buttons can have accessibility states 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityStateDisabled": true, "Clip": null, "FlowDirection": "LeftToRight", "Foreground": "#5C000000", @@ -482,6 +490,7 @@ exports[`ButtonTests Buttons can have accessibility states 1`] = ` exports[`ButtonTests Buttons can have custom colors 1`] = ` { + "AccessibilityRole": "Button", "AutomationId": "cancel_button", "Background": null, "BorderBrush": null, @@ -621,6 +630,7 @@ exports[`ButtonTests Buttons can have their accessibility and keyboard focus dis "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Button", "AutomationId": "accessibility_props", "Background": null, "BorderBrush": null, @@ -738,6 +748,7 @@ exports[`ButtonTests Buttons can have their accessibility and keyboard focus dis ], }, { + "AccessibilityRole": "Button", "AutomationId": "accessibility_props", "Background": null, "BorderBrush": null, @@ -855,6 +866,7 @@ exports[`ButtonTests Buttons can have their accessibility and keyboard focus dis ], }, { + "AccessibilityRole": "Button", "AutomationId": "accessibility_props", "Background": null, "BorderBrush": null, @@ -972,6 +984,7 @@ exports[`ButtonTests Buttons can have their accessibility and keyboard focus dis ], }, { + "AccessibilityRole": "Button", "AutomationId": "accessibility_props", "Background": null, "BorderBrush": null, @@ -1094,6 +1107,7 @@ exports[`ButtonTests Buttons can have their accessibility and keyboard focus dis exports[`ButtonTests Buttons have default styling 1`] = ` { + "AccessibilityRole": "Button", "AutomationId": "button_default_styling", "Background": null, "BorderBrush": null, diff --git a/packages/e2e-test-app/test/__snapshots__/FlyoutComponentTest.test.ts.snap b/packages/e2e-test-app/test/__snapshots__/FlyoutComponentTest.test.ts.snap index 65673b16c28..cfa1835fdf2 100644 --- a/packages/e2e-test-app/test/__snapshots__/FlyoutComponentTest.test.ts.snap +++ b/packages/e2e-test-app/test/__snapshots__/FlyoutComponentTest.test.ts.snap @@ -262,6 +262,7 @@ exports[`FlyoutTests Flyout 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Button", "Background": null, "BorderBrush": null, "BorderThickness": "0,0,0,0", @@ -398,6 +399,7 @@ exports[`FlyoutTests Flyout 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Button", "Background": null, "BorderBrush": null, "BorderThickness": "0,0,0,0", @@ -534,6 +536,7 @@ exports[`FlyoutTests Flyout 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Button", "Background": null, "BorderBrush": null, "BorderThickness": "0,0,0,0", diff --git a/packages/e2e-test-app/test/__snapshots__/LegacyControlStyleTest.test.ts.snap b/packages/e2e-test-app/test/__snapshots__/LegacyControlStyleTest.test.ts.snap index da08cd8f827..18649cbccdf 100644 --- a/packages/e2e-test-app/test/__snapshots__/LegacyControlStyleTest.test.ts.snap +++ b/packages/e2e-test-app/test/__snapshots__/LegacyControlStyleTest.test.ts.snap @@ -21,6 +21,7 @@ exports[`LegacyControlStyleTest ControlStyleTestWithRegularBorder #2 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Switch", "Background": "#33E1E1E1", "BorderBrush": "#55FF00FF", "BorderThickness": "1,1,1,1", @@ -655,6 +656,7 @@ exports[`LegacyControlStyleTest ControlStyleTestWithRegularBorder 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Switch", "Background": "#33E1E1E1", "BorderBrush": "#55FF00FF", "BorderThickness": "1,1,1,1", @@ -1289,6 +1291,7 @@ exports[`LegacyControlStyleTest ControlStyleTestWithRoundBorder 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Switch", "Background": "#33000000", "BorderBrush": "#5500FF00", "BorderThickness": "10,10,10,10", diff --git a/packages/e2e-test-app/test/__snapshots__/LegacyImageTest.test.ts.snap b/packages/e2e-test-app/test/__snapshots__/LegacyImageTest.test.ts.snap index 0240c767512..3b180f0e398 100644 --- a/packages/e2e-test-app/test/__snapshots__/LegacyImageTest.test.ts.snap +++ b/packages/e2e-test-app/test/__snapshots__/LegacyImageTest.test.ts.snap @@ -21,6 +21,7 @@ exports[`LegacyImageTest ImageRTLTest 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Image", "Left": 0, "Top": 0, "XamlType": "Windows.UI.Xaml.DependencyObject", @@ -50,6 +51,7 @@ exports[`LegacyImageTest ImageWithBorderTest 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Image", "Left": 10, "Top": 10, "XamlType": "Windows.UI.Xaml.DependencyObject", @@ -79,6 +81,7 @@ exports[`LegacyImageTest ImageWithoutBorderTest 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Image", "Left": 0, "Top": 0, "XamlType": "Windows.UI.Xaml.DependencyObject", @@ -108,6 +111,7 @@ exports[`LegacyImageTest ImageWithoutBorderTestOneMoreClick 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Image", "Left": 0, "Top": 0, "XamlType": "Windows.UI.Xaml.DependencyObject", diff --git a/packages/e2e-test-app/test/__snapshots__/PopupComponentTest.test.ts.snap b/packages/e2e-test-app/test/__snapshots__/PopupComponentTest.test.ts.snap index d9f42bd48df..be041a84cc4 100644 --- a/packages/e2e-test-app/test/__snapshots__/PopupComponentTest.test.ts.snap +++ b/packages/e2e-test-app/test/__snapshots__/PopupComponentTest.test.ts.snap @@ -270,6 +270,7 @@ exports[`PopupTests Popups can be anchored 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Button", "Background": null, "BorderBrush": null, "BorderThickness": "0,0,0,0", @@ -412,6 +413,7 @@ exports[`PopupTests Popups can have customized accessibility 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Button", "Background": null, "BorderBrush": null, "BorderThickness": "0,0,0,0", @@ -552,6 +554,7 @@ exports[`PopupTests Popups can have different placement 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Button", "Background": null, "BorderBrush": null, "BorderThickness": "0,0,0,0", diff --git a/packages/e2e-test-app/test/__snapshots__/PressableComponentTest.test.ts.snap b/packages/e2e-test-app/test/__snapshots__/PressableComponentTest.test.ts.snap index 3f057cc0922..11687ab22ac 100644 --- a/packages/e2e-test-app/test/__snapshots__/PressableComponentTest.test.ts.snap +++ b/packages/e2e-test-app/test/__snapshots__/PressableComponentTest.test.ts.snap @@ -184,6 +184,7 @@ exports[`PressableTests Pressables can have delayed event handlers 1`] = ` exports[`PressableTests Pressables can have event handlers 1`] = ` { + "AccessibilityRole": "Button", "AutomationId": "pressable_feedback_events_button", "Background": null, "BorderBrush": null, diff --git a/packages/e2e-test-app/test/__snapshots__/ScrollViewComponentTest.test.ts.snap b/packages/e2e-test-app/test/__snapshots__/ScrollViewComponentTest.test.ts.snap index 96520484cee..2fa17974f3f 100644 --- a/packages/e2e-test-app/test/__snapshots__/ScrollViewComponentTest.test.ts.snap +++ b/packages/e2e-test-app/test/__snapshots__/ScrollViewComponentTest.test.ts.snap @@ -3589,6 +3589,7 @@ exports[`ScrollViewTests ScrollViews can scroll an item list horizontally 1`] = exports[`ScrollViewTests ScrollViews can scroll an item list vertically 1`] = ` { + "AccessibilityRole": "Unknown", "AutomationId": "scroll_vertical", "Background": "#FFEEEEEE", "BorderBrush": "#00FFFFFF", diff --git a/packages/e2e-test-app/test/__snapshots__/SwitchComponentTest.test.ts.snap b/packages/e2e-test-app/test/__snapshots__/SwitchComponentTest.test.ts.snap index 36788e5e558..d1be7c351c8 100644 --- a/packages/e2e-test-app/test/__snapshots__/SwitchComponentTest.test.ts.snap +++ b/packages/e2e-test-app/test/__snapshots__/SwitchComponentTest.test.ts.snap @@ -2,6 +2,7 @@ exports[`SwitchTests Change events can be detected, event bottom 1`] = ` { + "AccessibilityRole": "Switch", "AutomationId": "event-switch-bottom", "Background": null, "BorderBrush": null, @@ -229,6 +230,7 @@ exports[`SwitchTests Change events can be detected, event bottom 1`] = ` exports[`SwitchTests Change events can be detected, event regression top 1`] = ` { + "AccessibilityRole": "Switch", "AutomationId": "event-switch-regression-top", "Background": null, "BorderBrush": null, @@ -456,6 +458,7 @@ exports[`SwitchTests Change events can be detected, event regression top 1`] = ` exports[`SwitchTests Change events can be detected, event top 1`] = ` { + "AccessibilityRole": "Switch", "AutomationId": "event-switch-top", "Background": null, "BorderBrush": null, @@ -683,6 +686,7 @@ exports[`SwitchTests Change events can be detected, event top 1`] = ` exports[`SwitchTests Change events can be detected, events regression bottom 1`] = ` { + "AccessibilityRole": "Switch", "AutomationId": "event-switch-regression-bottom", "Background": null, "BorderBrush": null, @@ -910,6 +914,7 @@ exports[`SwitchTests Change events can be detected, events regression bottom 1`] exports[`SwitchTests Controlled switch 1`] = ` { + "AccessibilityRole": "Switch", "AutomationId": "controlled-switch", "Background": null, "BorderBrush": null, @@ -1137,6 +1142,7 @@ exports[`SwitchTests Controlled switch 1`] = ` exports[`SwitchTests Custom colors can be provided, initial false 1`] = ` { + "AccessibilityRole": "Switch", "AutomationId": "initial-false-switch", "Background": null, "BorderBrush": null, @@ -1364,6 +1370,7 @@ exports[`SwitchTests Custom colors can be provided, initial false 1`] = ` exports[`SwitchTests Custom colors can be provided, initial true 1`] = ` { + "AccessibilityRole": "Switch", "AutomationId": "initial-true-switch", "Background": null, "BorderBrush": null, @@ -1591,6 +1598,7 @@ exports[`SwitchTests Custom colors can be provided, initial true 1`] = ` exports[`SwitchTests Switches can be disabled, initial false 1`] = ` { + "AccessibilityRole": "Switch", "AutomationId": "disabled-initial-off", "Background": null, "BorderBrush": null, @@ -1643,7 +1651,7 @@ exports[`SwitchTests Switches can be disabled, initial false 1`] = ` "XamlType": "Windows.UI.Xaml.Controls.Grid", "children": [ { - "Background": "#00000034", + "Background": "#00000040", "BorderBrush": null, "BorderThickness": "0,0,0,0", "Clip": null, @@ -1818,6 +1826,7 @@ exports[`SwitchTests Switches can be disabled, initial false 1`] = ` exports[`SwitchTests Switches can be disabled, initial true 1`] = ` { + "AccessibilityRole": "Switch", "AutomationId": "disabled-initial-on", "Background": null, "BorderBrush": null, @@ -1870,7 +1879,7 @@ exports[`SwitchTests Switches can be disabled, initial true 1`] = ` "XamlType": "Windows.UI.Xaml.Controls.Grid", "children": [ { - "Background": "#00000034", + "Background": "#00000040", "BorderBrush": null, "BorderThickness": "0,0,0,0", "Clip": null, @@ -2045,6 +2054,7 @@ exports[`SwitchTests Switches can be disabled, initial true 1`] = ` exports[`SwitchTests Switches can be set to true/false, initial false 1`] = ` { + "AccessibilityRole": "Switch", "AutomationId": "on-off-initial-off", "Background": null, "BorderBrush": null, @@ -2272,6 +2282,7 @@ exports[`SwitchTests Switches can be set to true/false, initial false 1`] = ` exports[`SwitchTests Switches can be set to true/false, initial true 1`] = ` { + "AccessibilityRole": "Switch", "AutomationId": "on-off-initial-on", "Background": null, "BorderBrush": null, @@ -2536,6 +2547,7 @@ exports[`SwitchTests Switches can have customized accessibility 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Switch", "Background": null, "BorderBrush": null, "BorderThickness": "0,0,0,0", @@ -2759,6 +2771,7 @@ exports[`SwitchTests Switches can have customized accessibility 1`] = ` ], }, { + "AccessibilityRole": "Switch", "Background": null, "BorderBrush": null, "BorderThickness": "0,0,0,0", @@ -3002,6 +3015,7 @@ exports[`SwitchTests Switches can have customized accessibility 1`] = ` "XamlType": "Microsoft.ReactNative.ViewPanel", "children": [ { + "AccessibilityRole": "Switch", "Background": null, "BorderBrush": null, "BorderThickness": "0,0,0,0", @@ -3225,6 +3239,7 @@ exports[`SwitchTests Switches can have customized accessibility 1`] = ` ], }, { + "AccessibilityRole": "Switch", "Background": null, "BorderBrush": null, "BorderThickness": "0,0,0,0", diff --git a/packages/e2e-test-app/test/__snapshots__/ViewComponentTest.test.ts.snap b/packages/e2e-test-app/test/__snapshots__/ViewComponentTest.test.ts.snap index a6842713644..e8a3f08120c 100644 --- a/packages/e2e-test-app/test/__snapshots__/ViewComponentTest.test.ts.snap +++ b/packages/e2e-test-app/test/__snapshots__/ViewComponentTest.test.ts.snap @@ -234,6 +234,7 @@ exports[`ViewTests Views can have a custom nativeID 1`] = ` exports[`ViewTests Views can have accessibility customization 1`] = ` { + "AccessibilityRole": "Unknown", "AutomationId": "accessibility", "Background": null, "BorderBrush": null, diff --git a/packages/e2e-test-app/windows/RNTesterApp/MainPage.xaml.cs b/packages/e2e-test-app/windows/RNTesterApp/MainPage.xaml.cs index 07d11ccfe40..c65cc149828 100644 --- a/packages/e2e-test-app/windows/RNTesterApp/MainPage.xaml.cs +++ b/packages/e2e-test-app/windows/RNTesterApp/MainPage.xaml.cs @@ -57,6 +57,19 @@ JsonObject ListErrors(JsonValue payload) return result; } + private static PropertyValueConverter GetEnumConverter() where T : struct + { + return (propertyValue) => + { + if (propertyValue is T pvAsT) + { + return pvAsT.ToString(); + } + + return $"Error: \"{propertyValue}\" is not of type { nameof(T) }."; + }; + } + JsonObject DumpVisualTree(JsonValue payload) { var payloadObj = payload.GetObject(); @@ -74,19 +87,18 @@ JsonObject DumpVisualTree(JsonValue payload) var attachedProperties = new AttachedProperty[] { new AttachedProperty() { Name = "Top", Property = Microsoft.ReactNative.ViewPanel.TopProperty }, new AttachedProperty() { Name = "Left", Property = Microsoft.ReactNative.ViewPanel.LeftProperty }, - new AttachedProperty() { Name = "Tooltip", Property = Windows.UI.Xaml.Controls.ToolTipService.ToolTipProperty }, - new AttachedProperty() { Name = "AutomationLevel", Property = Windows.UI.Xaml.Automation.AutomationProperties.LevelProperty }, - new AttachedProperty() { Name = "AutomationSizeOfSet", Property = Windows.UI.Xaml.Automation.AutomationProperties.SizeOfSetProperty }, - new AttachedProperty() { Name = "AutomationPositionInSet", Property = Windows.UI.Xaml.Automation.AutomationProperties.PositionInSetProperty }, - new AttachedProperty() { Name = "AccessibilityRole", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityRoleProperty }, - new AttachedProperty() { Name = "AccessibilityStateSelected", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateSelectedProperty }, - new AttachedProperty() { Name = "AccessibilityStateDisabled", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateDisabledProperty }, - new AttachedProperty() { Name = "AccessibilityStateChecked", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateCheckedProperty }, - new AttachedProperty() { Name = "AccessibilityStateBusy", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateBusyProperty }, - new AttachedProperty() { Name = "AccessibilityStateExpanded", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateExpandedProperty }, + new AttachedProperty() { Name = "Tooltip", Property = Windows.UI.Xaml.Controls.ToolTipService.ToolTipProperty, ExcludeIfValueIsUnset = true }, + new AttachedProperty() { Name = "AutomationLevel", Property = Windows.UI.Xaml.Automation.AutomationProperties.LevelProperty, ExcludeIfValueIsUnset = true }, + new AttachedProperty() { Name = "AutomationSizeOfSet", Property = Windows.UI.Xaml.Automation.AutomationProperties.SizeOfSetProperty, ExcludeIfValueIsUnset = true }, + new AttachedProperty() { Name = "AutomationPositionInSet", Property = Windows.UI.Xaml.Automation.AutomationProperties.PositionInSetProperty, ExcludeIfValueIsUnset = true }, + new AttachedProperty() { Name = "AccessibilityRole", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityRoleProperty, ExcludeIfValueIsUnset = true, PropertyValueConverter = GetEnumConverter() }, + new AttachedProperty() { Name = "AccessibilityStateSelected", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateSelectedProperty, ExcludeIfValueIsUnset = true }, + new AttachedProperty() { Name = "AccessibilityStateDisabled", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateDisabledProperty, ExcludeIfValueIsUnset = true }, + new AttachedProperty() { Name = "AccessibilityStateChecked", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateCheckedProperty, ExcludeIfValueIsUnset = true, PropertyValueConverter = GetEnumConverter()}, + new AttachedProperty() { Name = "AccessibilityStateBusy", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateBusyProperty, ExcludeIfValueIsUnset = true }, + new AttachedProperty() { Name = "AccessibilityStateExpanded", Property = Microsoft.ReactNative.DynamicAutomationProperties.AccessibilityStateExpandedProperty, ExcludeIfValueIsUnset = true }, }; var rootDump = VisualTreeDumper.DumpTree(this, null, additionalProperties, attachedProperties); - rootDump = rootDump.Replace(" False", " false").Replace(" True", " true"); // Temporary workaround until we can fix upstream to produce correct JSON boolean values var element = VisualTreeDumper.FindElementByAutomationId(JsonObject.Parse(rootDump), accessibilityId); if (element != null) return element; diff --git a/packages/e2e-test-app/windows/RNTesterApp/RNTesterApp.csproj b/packages/e2e-test-app/windows/RNTesterApp/RNTesterApp.csproj index 64ad4b13faf..982b8f3eadc 100644 --- a/packages/e2e-test-app/windows/RNTesterApp/RNTesterApp.csproj +++ b/packages/e2e-test-app/windows/RNTesterApp/RNTesterApp.csproj @@ -142,7 +142,7 @@ - 1.0.9 + 1.0.10 diff --git a/packages/e2e-test-app/windows/RNTesterApp/packages.lock.json b/packages/e2e-test-app/windows/RNTesterApp/packages.lock.json index a31212e0e21..5ddda9bb068 100644 --- a/packages/e2e-test-app/windows/RNTesterApp/packages.lock.json +++ b/packages/e2e-test-app/windows/RNTesterApp/packages.lock.json @@ -25,9 +25,9 @@ }, "XamlTreeDump": { "type": "Direct", - "requested": "[1.0.9, )", - "resolved": "1.0.9", - "contentHash": "rvh/RZghhSG28PDL1dw56nTZRN0/ViV2TIja/ykU9FHn0gtM8pwtgD8Ebo1nobu0QnSjn8Cg6Ncu39VV19rkrw==" + "requested": "[1.0.10, )", + "resolved": "1.0.10", + "contentHash": "JZU+uldJihK7doefnCjduIcwn6VSy/+7BB1X+IHV2FCcpblf35+XdUcR8nxhtk7vCEVMHZ9FECVcR0g3az9pCA==" }, "boost": { "type": "Transitive", From 3155ace9c7e3416b707ad0d93dc2ac4a4b33fb76 Mon Sep 17 00:00:00 2001 From: "Jon Thysell (JAUNTY)" Date: Wed, 28 Jun 2023 15:21:30 -0700 Subject: [PATCH 8/9] fix snapshot --- .../test/__snapshots__/SwitchComponentTest.test.ts.snap | 4 ++-- packages/e2e-test-app/windows/RNTesterApp/packages.lock.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/e2e-test-app/test/__snapshots__/SwitchComponentTest.test.ts.snap b/packages/e2e-test-app/test/__snapshots__/SwitchComponentTest.test.ts.snap index d1be7c351c8..a0e93f9ab19 100644 --- a/packages/e2e-test-app/test/__snapshots__/SwitchComponentTest.test.ts.snap +++ b/packages/e2e-test-app/test/__snapshots__/SwitchComponentTest.test.ts.snap @@ -1651,7 +1651,7 @@ exports[`SwitchTests Switches can be disabled, initial false 1`] = ` "XamlType": "Windows.UI.Xaml.Controls.Grid", "children": [ { - "Background": "#00000040", + "Background": "#00000034", "BorderBrush": null, "BorderThickness": "0,0,0,0", "Clip": null, @@ -1879,7 +1879,7 @@ exports[`SwitchTests Switches can be disabled, initial true 1`] = ` "XamlType": "Windows.UI.Xaml.Controls.Grid", "children": [ { - "Background": "#00000040", + "Background": "#00000034", "BorderBrush": null, "BorderThickness": "0,0,0,0", "Clip": null, diff --git a/packages/e2e-test-app/windows/RNTesterApp/packages.lock.json b/packages/e2e-test-app/windows/RNTesterApp/packages.lock.json index 5ddda9bb068..6547ae7a3fc 100644 --- a/packages/e2e-test-app/windows/RNTesterApp/packages.lock.json +++ b/packages/e2e-test-app/windows/RNTesterApp/packages.lock.json @@ -27,7 +27,7 @@ "type": "Direct", "requested": "[1.0.10, )", "resolved": "1.0.10", - "contentHash": "JZU+uldJihK7doefnCjduIcwn6VSy/+7BB1X+IHV2FCcpblf35+XdUcR8nxhtk7vCEVMHZ9FECVcR0g3az9pCA==" + "contentHash": "2+6dKEFYpSP7w2QA4hkOtzPphpGlYHvW92/MTkloNNXH5ejy8qt64LhpIGzGX6FC42p4SwGSrZCXJjdvxr7bRw==" }, "boost": { "type": "Transitive", From 8568da27e539d494f6bbf20f207a52681cb7cd1f Mon Sep 17 00:00:00 2001 From: Jon Thysell Date: Wed, 28 Jun 2023 16:33:15 -0700 Subject: [PATCH 9/9] Fix `DynamicAutomationPeer::IsSelected()` --- vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.cpp b/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.cpp index 219615357ab..96de3361c8e 100644 --- a/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.cpp +++ b/vnext/Microsoft.ReactNative/Views/DynamicAutomationPeer.cpp @@ -200,10 +200,10 @@ winrt::com_array DynamicAutomationPeer::GetSel bool DynamicAutomationPeer::IsSelected() const { bool selected = false; try { - return DynamicAutomationProperties::GetAccessibilityStateSelected(Owner()); + selected = DynamicAutomationProperties::GetAccessibilityStateSelected(Owner()); } catch (...) { } - return false; + return selected; } winrt::IRawElementProviderSimple DynamicAutomationPeer::SelectionContainer() const {