Skip to content

Commit

Permalink
Fuchsia a11y actions (flutter#16321)
Browse files Browse the repository at this point in the history
  • Loading branch information
dnfield committed Feb 5, 2020
1 parent e3e6de2 commit e24ec59
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 7 deletions.
55 changes: 54 additions & 1 deletion shell/platform/fuchsia/flutter/accessibility_bridge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
23 changes: 17 additions & 6 deletions shell/platform/fuchsia/flutter/accessibility_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand Down
62 changes: 62 additions & 0 deletions shell/platform/fuchsia/flutter/accessibility_bridge_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand All @@ -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(),
Expand Down Expand Up @@ -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
7 changes: 7 additions & 0 deletions shell/platform/fuchsia/flutter/platform_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions shell/platform/fuchsia/flutter/platform_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit e24ec59

Please sign in to comment.