mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Fuchsia a11y actions (flutter/engine#16321)
This commit is contained in:
parent
d319ee469d
commit
8e419f3347
@ -281,12 +281,65 @@ void AccessibilityBridge::UpdateScreenRects(
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<flutter::SemanticsAction>
|
||||
AccessibilityBridge::GetFlutterSemanticsAction(
|
||||
fuchsia::accessibility::semantics::Action fuchsia_action,
|
||||
uint32_t node_id) {
|
||||
switch (fuchsia_action) {
|
||||
// The default action associated with the element.
|
||||
case fuchsia::accessibility::semantics::Action::DEFAULT:
|
||||
return flutter::SemanticsAction::kTap;
|
||||
// The secondary action associated with the element. This may correspond to
|
||||
// a long press (touchscreens) or right click (mouse).
|
||||
case fuchsia::accessibility::semantics::Action::SECONDARY:
|
||||
return flutter::SemanticsAction::kLongPress;
|
||||
// Set (input/non-accessibility) focus on this element.
|
||||
case fuchsia::accessibility::semantics::Action::SET_FOCUS:
|
||||
FML_DLOG(WARNING)
|
||||
<< "Unsupported action SET_FOCUS sent for accessibility node "
|
||||
<< node_id;
|
||||
return {};
|
||||
// Set the element's value.
|
||||
case fuchsia::accessibility::semantics::Action::SET_VALUE:
|
||||
FML_DLOG(WARNING)
|
||||
<< "Unsupported action SET_VALUE sent for accessibility node "
|
||||
<< node_id;
|
||||
return {};
|
||||
// Scroll node to make it visible.
|
||||
case fuchsia::accessibility::semantics::Action::SHOW_ON_SCREEN:
|
||||
return flutter::SemanticsAction::kShowOnScreen;
|
||||
default:
|
||||
FML_DLOG(WARNING) << "Unexpected action "
|
||||
<< static_cast<int32_t>(fuchsia_action)
|
||||
<< " sent for accessibility node " << node_id;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// |fuchsia::accessibility::semantics::SemanticListener|
|
||||
void AccessibilityBridge::OnAccessibilityActionRequested(
|
||||
uint32_t node_id,
|
||||
fuchsia::accessibility::semantics::Action action,
|
||||
fuchsia::accessibility::semantics::SemanticListener::
|
||||
OnAccessibilityActionRequestedCallback callback) {}
|
||||
OnAccessibilityActionRequestedCallback callback) {
|
||||
if (nodes_.find(node_id) == nodes_.end()) {
|
||||
FML_LOG(ERROR) << "Attempted to send accessibility action "
|
||||
<< static_cast<int32_t>(action)
|
||||
<< " to unkonwn node id: " << node_id;
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
|
||||
std::optional<flutter::SemanticsAction> flutter_action =
|
||||
GetFlutterSemanticsAction(action, node_id);
|
||||
if (!flutter_action.has_value()) {
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
delegate_.DispatchSemanticsAction(static_cast<int32_t>(node_id),
|
||||
flutter_action.value());
|
||||
callback(true);
|
||||
}
|
||||
|
||||
// |fuchsia::accessibility::semantics::SemanticListener|
|
||||
void AccessibilityBridge::HitTest(
|
||||
|
||||
@ -44,6 +44,8 @@ class AccessibilityBridge
|
||||
class Delegate {
|
||||
public:
|
||||
virtual void SetSemanticsEnabled(bool enabled) = 0;
|
||||
virtual void DispatchSemanticsAction(int32_t node_id,
|
||||
flutter::SemanticsAction action) = 0;
|
||||
};
|
||||
|
||||
// TODO(MI4-2531, FIDL-718): Remove this. We shouldn't be worried about
|
||||
@ -91,6 +93,13 @@ class AccessibilityBridge
|
||||
fuchsia::accessibility::semantics::SemanticListener::HitTestCallback
|
||||
callback) override;
|
||||
|
||||
// |fuchsia::accessibility::semantics::SemanticListener|
|
||||
void OnAccessibilityActionRequested(
|
||||
uint32_t node_id,
|
||||
fuchsia::accessibility::semantics::Action action,
|
||||
fuchsia::accessibility::semantics::SemanticListener::
|
||||
OnAccessibilityActionRequestedCallback callback) override;
|
||||
|
||||
private:
|
||||
// Holds only the fields we need for hit testing.
|
||||
// In particular, it adds a screen_rect field to flutter::SemanticsNode.
|
||||
@ -164,12 +173,14 @@ class AccessibilityBridge
|
||||
// Assumes that SemanticsNode::screen_rect is up to date.
|
||||
std::optional<int32_t> GetHitNode(int32_t node_id, float x, float y);
|
||||
|
||||
// |fuchsia::accessibility::semantics::SemanticListener|
|
||||
void OnAccessibilityActionRequested(
|
||||
uint32_t node_id,
|
||||
fuchsia::accessibility::semantics::Action action,
|
||||
fuchsia::accessibility::semantics::SemanticListener::
|
||||
OnAccessibilityActionRequestedCallback callback) override;
|
||||
// Converts a fuchsia::accessibility::semantics::Action to a
|
||||
// flutter::SemanticsAction.
|
||||
//
|
||||
// The node_id parameter is used for printing warnings about unsupported
|
||||
// action types.
|
||||
std::optional<flutter::SemanticsAction> GetFlutterSemanticsAction(
|
||||
fuchsia::accessibility::semantics::Action fuchsia_action,
|
||||
uint32_t node_id);
|
||||
|
||||
// |fuchsia::accessibility::semantics::SemanticListener|
|
||||
void OnSemanticsModeChanged(bool enabled,
|
||||
|
||||
@ -23,7 +23,13 @@ class AccessibilityBridgeTestDelegate
|
||||
: public flutter_runner::AccessibilityBridge::Delegate {
|
||||
public:
|
||||
void SetSemanticsEnabled(bool enabled) override { enabled_ = enabled; }
|
||||
void DispatchSemanticsAction(int32_t node_id,
|
||||
flutter::SemanticsAction action) override {
|
||||
actions.push_back(std::make_pair(node_id, action));
|
||||
}
|
||||
|
||||
bool enabled() { return enabled_; }
|
||||
std::vector<std::pair<int32_t, flutter::SemanticsAction>> actions;
|
||||
|
||||
private:
|
||||
bool enabled_;
|
||||
@ -50,6 +56,7 @@ class AccessibilityBridgeTest : public testing::Test {
|
||||
/*flags*/ 0u, &view_ref_control_.reference, &view_ref_.reference);
|
||||
EXPECT_EQ(status, ZX_OK);
|
||||
|
||||
accessibility_delegate_.actions.clear();
|
||||
accessibility_bridge_ =
|
||||
std::make_unique<flutter_runner::AccessibilityBridge>(
|
||||
accessibility_delegate_, services_provider_.service_directory(),
|
||||
@ -364,4 +371,59 @@ TEST_F(AccessibilityBridgeTest, HitTest) {
|
||||
accessibility_bridge_->HitTest({30, 30}, callback);
|
||||
EXPECT_EQ(hit_node_id, 4u);
|
||||
}
|
||||
|
||||
TEST_F(AccessibilityBridgeTest, Actions) {
|
||||
flutter::SemanticsNode node0;
|
||||
node0.id = 0;
|
||||
|
||||
flutter::SemanticsNode node1;
|
||||
node1.id = 1;
|
||||
|
||||
node0.childrenInTraversalOrder = {1};
|
||||
node0.childrenInHitTestOrder = {1};
|
||||
|
||||
accessibility_bridge_->AddSemanticsNodeUpdate({
|
||||
{0, node0},
|
||||
{1, node1},
|
||||
});
|
||||
RunLoopUntilIdle();
|
||||
|
||||
auto handled_callback = [](bool handled) { EXPECT_TRUE(handled); };
|
||||
auto unhandled_callback = [](bool handled) { EXPECT_FALSE(handled); };
|
||||
|
||||
accessibility_bridge_->OnAccessibilityActionRequested(
|
||||
0u, fuchsia::accessibility::semantics::Action::DEFAULT, handled_callback);
|
||||
EXPECT_EQ(accessibility_delegate_.actions.size(), 1u);
|
||||
EXPECT_EQ(accessibility_delegate_.actions.back(),
|
||||
std::make_pair(0, flutter::SemanticsAction::kTap));
|
||||
|
||||
accessibility_bridge_->OnAccessibilityActionRequested(
|
||||
0u, fuchsia::accessibility::semantics::Action::SECONDARY,
|
||||
handled_callback);
|
||||
EXPECT_EQ(accessibility_delegate_.actions.size(), 2u);
|
||||
EXPECT_EQ(accessibility_delegate_.actions.back(),
|
||||
std::make_pair(0, flutter::SemanticsAction::kLongPress));
|
||||
|
||||
accessibility_bridge_->OnAccessibilityActionRequested(
|
||||
0u, fuchsia::accessibility::semantics::Action::SET_FOCUS,
|
||||
unhandled_callback);
|
||||
EXPECT_EQ(accessibility_delegate_.actions.size(), 2u);
|
||||
|
||||
accessibility_bridge_->OnAccessibilityActionRequested(
|
||||
0u, fuchsia::accessibility::semantics::Action::SET_VALUE,
|
||||
unhandled_callback);
|
||||
EXPECT_EQ(accessibility_delegate_.actions.size(), 2u);
|
||||
|
||||
accessibility_bridge_->OnAccessibilityActionRequested(
|
||||
0u, fuchsia::accessibility::semantics::Action::SHOW_ON_SCREEN,
|
||||
handled_callback);
|
||||
EXPECT_EQ(accessibility_delegate_.actions.size(), 3u);
|
||||
EXPECT_EQ(accessibility_delegate_.actions.back(),
|
||||
std::make_pair(0, flutter::SemanticsAction::kShowOnScreen));
|
||||
|
||||
accessibility_bridge_->OnAccessibilityActionRequested(
|
||||
2u, fuchsia::accessibility::semantics::Action::DEFAULT,
|
||||
unhandled_callback);
|
||||
EXPECT_EQ(accessibility_delegate_.actions.size(), 3u);
|
||||
}
|
||||
} // namespace flutter_runner_test
|
||||
|
||||
@ -602,6 +602,13 @@ void PlatformView::SetSemanticsEnabled(bool enabled) {
|
||||
}
|
||||
}
|
||||
|
||||
// |flutter::PlatformView|
|
||||
// |flutter_runner::AccessibilityBridge::Delegate|
|
||||
void PlatformView::DispatchSemanticsAction(int32_t node_id,
|
||||
flutter::SemanticsAction action) {
|
||||
flutter::PlatformView::DispatchSemanticsAction(node_id, action, {});
|
||||
}
|
||||
|
||||
// |flutter::PlatformView|
|
||||
void PlatformView::UpdateSemantics(
|
||||
flutter::SemanticsNodeUpdates update,
|
||||
|
||||
@ -69,6 +69,10 @@ class PlatformView final : public flutter::PlatformView,
|
||||
// |flutter_runner::AccessibilityBridge::Delegate|
|
||||
void SetSemanticsEnabled(bool enabled) override;
|
||||
|
||||
// |flutter_runner::AccessibilityBridge::Delegate|
|
||||
void DispatchSemanticsAction(int32_t node_id,
|
||||
flutter::SemanticsAction action) override;
|
||||
|
||||
// |PlatformView|
|
||||
flutter::PointerDataDispatcherMaker GetDispatcherMaker() override;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user