diff --git a/shell/platform/fuchsia/flutter/accessibility_bridge.cc b/shell/platform/fuchsia/flutter/accessibility_bridge.cc index 8d69efcb0c9bd..93b12e17b742c 100644 --- a/shell/platform/fuchsia/flutter/accessibility_bridge.cc +++ b/shell/platform/fuchsia/flutter/accessibility_bridge.cc @@ -160,6 +160,10 @@ fuchsia::accessibility::semantics::Role AccessibilityBridge::GetNodeRole( return fuchsia::accessibility::semantics::Role::TEXT_FIELD; } + if (node.HasFlag(flutter::SemanticsFlags::kIsLink)) { + return fuchsia::accessibility::semantics::Role::LINK; + } + if (node.HasFlag(flutter::SemanticsFlags::kIsSlider)) { return fuchsia::accessibility::semantics::Role::SLIDER; } @@ -170,6 +174,7 @@ fuchsia::accessibility::semantics::Role AccessibilityBridge::GetNodeRole( if (node.HasFlag(flutter::SemanticsFlags::kIsImage)) { return fuchsia::accessibility::semantics::Role::IMAGE; } + // If a flutter node supports the kIncrease or kDecrease actions, it can be // treated as a slider control by assistive technology. This is important // because users have special gestures to deal with sliders, and Fuchsia API @@ -178,6 +183,18 @@ fuchsia::accessibility::semantics::Role AccessibilityBridge::GetNodeRole( node.HasAction(flutter::SemanticsAction::kDecrease)) { return fuchsia::accessibility::semantics::Role::SLIDER; } + + // If a flutter node has a checked state, then we assume it is either a + // checkbox or a radio button. We distinguish between checkboxes and + // radio buttons based on membership in a mutually exclusive group. + if (!node.HasFlag(flutter::SemanticsFlags::kHasCheckedState)) { + if (node.HasFlag(flutter::SemanticsFlags::kIsInMutuallyExclusiveGroup)) { + return fuchsia::accessibility::semantics::Role::RADIO_BUTTON; + } else { + return fuchsia::accessibility::semantics::Role::CHECK_BOX; + } + } + return fuchsia::accessibility::semantics::Role::UNKNOWN; } diff --git a/shell/platform/fuchsia/flutter/accessibility_bridge_unittest.cc b/shell/platform/fuchsia/flutter/accessibility_bridge_unittest.cc index 206bca0209bb7..9ad491ff65c00 100644 --- a/shell/platform/fuchsia/flutter/accessibility_bridge_unittest.cc +++ b/shell/platform/fuchsia/flutter/accessibility_bridge_unittest.cc @@ -141,6 +141,29 @@ TEST_F(AccessibilityBridgeTest, UpdatesNodeRoles) { node4.flags |= static_cast<int>(flutter::SemanticsFlags::kIsSlider); updates.emplace(4, node4); + flutter::SemanticsNode node5; + node5.childrenInTraversalOrder = {}; + node5.childrenInHitTestOrder = {}; + node5.id = 5; + node5.flags |= static_cast<int>(flutter::SemanticsFlags::kIsLink); + updates.emplace(5, node5); + + flutter::SemanticsNode node6; + node6.childrenInTraversalOrder = {}; + node6.childrenInHitTestOrder = {}; + node6.id = 6; + node6.flags |= static_cast<int>(flutter::SemanticsFlags::kHasCheckedState); + node6.flags |= + static_cast<int>(flutter::SemanticsFlags::kIsInMutuallyExclusiveGroup); + updates.emplace(6, node6); + + flutter::SemanticsNode node7; + node7.childrenInTraversalOrder = {}; + node7.childrenInHitTestOrder = {}; + node7.id = 7; + node7.flags |= static_cast<int>(flutter::SemanticsFlags::kHasCheckedState); + updates.emplace(7, node7); + accessibility_bridge_->AddSemanticsNodeUpdate(std::move(updates), 1.f); RunLoopUntilIdle(); @@ -150,12 +173,15 @@ TEST_F(AccessibilityBridgeTest, UpdatesNodeRoles) { {1u, fuchsia::accessibility::semantics::Role::HEADER}, {2u, fuchsia::accessibility::semantics::Role::IMAGE}, {3u, fuchsia::accessibility::semantics::Role::TEXT_FIELD}, - {4u, fuchsia::accessibility::semantics::Role::SLIDER}}; + {4u, fuchsia::accessibility::semantics::Role::SLIDER}, + {5u, fuchsia::accessibility::semantics::Role::LINK}, + {6u, fuchsia::accessibility::semantics::Role::RADIO_BUTTON}, + {7u, fuchsia::accessibility::semantics::Role::CHECK_BOX}}; EXPECT_EQ(0, semantics_manager_.DeleteCount()); EXPECT_EQ(1, semantics_manager_.UpdateCount()); EXPECT_EQ(1, semantics_manager_.CommitCount()); - EXPECT_EQ(5U, semantics_manager_.LastUpdatedNodes().size()); + EXPECT_EQ(8u, semantics_manager_.LastUpdatedNodes().size()); for (const auto& node : semantics_manager_.LastUpdatedNodes()) { ExpectNodeHasRole(node, roles_by_node_id); }