Commit d2e33ef0 authored by Randy Rossi's avatar Randy Rossi Committed by Commit Bot

Add ANNOUNCE event type and sort keys to semantics nodes

This adds an ANNOUNCE event type to let the flutter
bridge client use the tts engine to make announcements.

Also adds sort keys in order to override the default
ordering for nodes.  Subsequent CL will implement
the sorting.

Bug: None
Test: unittest
Change-Id: I4c0f00ad2318208854f1d14c63f34307fe2ddc22
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2446552Reviewed-by: default avatarDaniel Nicoara <dnicoara@chromium.org>
Commit-Queue: Randy Rossi <rmrossi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#814185}
parent c66038fc
...@@ -97,6 +97,15 @@ void AXTreeSourceFlutter::NotifyAccessibilityEvent( ...@@ -97,6 +97,15 @@ void AXTreeSourceFlutter::NotifyAccessibilityEvent(
} }
// First find out if we know what to do with this event type from flutter. // First find out if we know what to do with this event type from flutter.
if (event_data->event_type() ==
gallium::castos::OnAccessibilityEventRequest_EventType_ANNOUNCEMENT) {
if (!event_data->has_text())
return;
SubmitTTS(event_data->text());
return;
}
ax::mojom::Event translated_event = ToAXEvent(event_data->event_type()); ax::mojom::Event translated_event = ToAXEvent(event_data->event_type());
if (translated_event == ax::mojom::Event::kNone) { if (translated_event == ax::mojom::Event::kNone) {
LOG(INFO) << "Ignoring unknown flutter ax event " LOG(INFO) << "Ignoring unknown flutter ax event "
...@@ -566,13 +575,7 @@ void AXTreeSourceFlutter::HandleNativeTTS() { ...@@ -566,13 +575,7 @@ void AXTreeSourceFlutter::HandleNativeTTS() {
if (prev_it != native_tts_name_cache_.end() && if (prev_it != native_tts_name_cache_.end() &&
prev_it->second != it.second) { prev_it->second != it.second) {
// Send to TTS controller. // Send to TTS controller.
std::unique_ptr<content::TtsUtterance> utterance = SubmitTTS(it.second);
content::TtsUtterance::Create(browser_context_);
utterance->SetText(it.second);
auto* tts_controller = content::TtsController::GetInstance();
tts_controller->Stop();
tts_controller->SpeakOrEnqueue(std::move(utterance));
} }
} }
...@@ -660,12 +663,7 @@ void AXTreeSourceFlutter::HandleRoutes(std::vector<ui::AXEvent>* events) { ...@@ -660,12 +663,7 @@ void AXTreeSourceFlutter::HandleRoutes(std::vector<ui::AXEvent>* events) {
focus_event.event_from = ax::mojom::EventFrom::kNone; focus_event.event_from = ax::mojom::EventFrom::kNone;
// Speak it. // Speak it.
std::unique_ptr<content::TtsUtterance> utterance = SubmitTTS(name);
content::TtsUtterance::Create(browser_context_);
utterance->SetText(name);
auto* tts_controller = content::TtsController::GetInstance();
tts_controller->Stop();
tts_controller->SpeakOrEnqueue(std::move(utterance));
} }
} }
} }
...@@ -754,6 +752,17 @@ int32_t AXTreeSourceFlutter::FindFirstFocusableNodeId() { ...@@ -754,6 +752,17 @@ int32_t AXTreeSourceFlutter::FindFirstFocusableNodeId() {
return root_id_; return root_id_;
} }
void AXTreeSourceFlutter::SubmitTTS(const std::string& text) {
std::unique_ptr<content::TtsUtterance> utterance =
content::TtsUtterance::Create(browser_context_);
utterance->SetText(text);
auto* tts_controller = content::TtsController::GetInstance();
tts_controller->Stop();
tts_controller->SpeakOrEnqueue(std::move(utterance));
}
void AXTreeSourceFlutter::UpdateTree() { void AXTreeSourceFlutter::UpdateTree() {
// Update the tree with last known flutter nodes. // Update the tree with last known flutter nodes.
// TODO: A more efficient update would be to isolate just the parent node // TODO: A more efficient update would be to isolate just the parent node
......
...@@ -167,6 +167,9 @@ class AXTreeSourceFlutter : public ui::AXTreeSource<FlutterSemanticsNode*, ...@@ -167,6 +167,9 @@ class AXTreeSourceFlutter : public ui::AXTreeSource<FlutterSemanticsNode*,
// the root node id. // the root node id.
int32_t FindFirstFocusableNodeId(); int32_t FindFirstFocusableNodeId();
// Submit text to TTS engine.
void SubmitTTS(const std::string& text);
std::unique_ptr<AXTreeFlutterSerializer> current_tree_serializer_; std::unique_ptr<AXTreeFlutterSerializer> current_tree_serializer_;
int32_t root_id_; int32_t root_id_;
int32_t window_id_; int32_t window_id_;
......
...@@ -21,6 +21,7 @@ using ::testing::StrictMock; ...@@ -21,6 +21,7 @@ using ::testing::StrictMock;
using ::gallium::castos::ActionProperties; using ::gallium::castos::ActionProperties;
using ::gallium::castos::BooleanProperties; using ::gallium::castos::BooleanProperties;
using ::gallium::castos::OnAccessibilityEventRequest; using ::gallium::castos::OnAccessibilityEventRequest;
using ::gallium::castos::OnAccessibilityEventRequest_EventType_ANNOUNCEMENT;
using ::gallium::castos::OnAccessibilityEventRequest_EventType_CONTENT_CHANGED; using ::gallium::castos::OnAccessibilityEventRequest_EventType_CONTENT_CHANGED;
using ::gallium::castos::OnAccessibilityEventRequest_EventType_FOCUSED; using ::gallium::castos::OnAccessibilityEventRequest_EventType_FOCUSED;
using ::gallium::castos::Rect; using ::gallium::castos::Rect;
...@@ -844,5 +845,27 @@ TEST_F(AXTreeSourceFlutterTest, ScopesRoute) { ...@@ -844,5 +845,27 @@ TEST_F(AXTreeSourceFlutterTest, ScopesRoute) {
ASSERT_EQ(0, tree_data.focus_id); ASSERT_EQ(0, tree_data.focus_id);
} }
TEST_F(AXTreeSourceFlutterTest, Announce) {
// Install a mock tts platform
auto* tts_controller = content::TtsController::GetInstance();
content::MockTtsPlatformImpl mock_tts_platform;
tts_controller->SetTtsPlatform(&mock_tts_platform);
// Setup some mocks required for tts platform impl
content::MockContentBrowserClient mock_content_browser_client;
content::MockContentClient client;
content::SetContentClient(&client);
content::SetBrowserClientForTesting(&mock_content_browser_client);
// Setup an announcement event
OnAccessibilityEventRequest event;
event.set_event_type(OnAccessibilityEventRequest_EventType_ANNOUNCEMENT);
event.set_text("Say this please");
CallNotifyAccessibilityEvent(&event);
// Child 3 should have been spoken
ASSERT_EQ(mock_tts_platform.GetLastSpokenUtterance(), "Say this please");
}
} // namespace accessibility } // namespace accessibility
} // namespace chromecast } // namespace chromecast
...@@ -55,7 +55,7 @@ message ActionProperties { ...@@ -55,7 +55,7 @@ message ActionProperties {
optional bool dismiss = 19; optional bool dismiss = 19;
optional bool move_cursor_forward_by_word = 20; optional bool move_cursor_forward_by_word = 20;
optional bool move_cursor_backward_by_word = 21; optional bool move_cursor_backward_by_word = 21;
}; }
message CustomAction { message CustomAction {
optional int32 id = 1; optional int32 id = 1;
...@@ -63,6 +63,12 @@ message CustomAction { ...@@ -63,6 +63,12 @@ message CustomAction {
} }
message SemanticsNode { message SemanticsNode {
enum SortKeyType {
UNSPECIFIED = 0;
// sort_key_value and sort_key_order specified.
ORDINAL = 1;
}
optional int32 node_id = 1; optional int32 node_id = 1;
optional Rect bounds_in_screen = 2; optional Rect bounds_in_screen = 2;
optional int32 window_id = 3; optional int32 window_id = 3;
...@@ -86,6 +92,14 @@ message SemanticsNode { ...@@ -86,6 +92,14 @@ message SemanticsNode {
// is provided by a platform plugin or some other native backed // is provided by a platform plugin or some other native backed
// entity. // entity.
optional string plugin_id = 20; optional string plugin_id = 20;
optional SortKeyType sort_key_type = 21;
// For sort_key_type ORDINAL: An optional name that will group
// this sort key with other sort keys of the same name.
optional string sort_key_value = 22;
// For sort_key_type ORDINAL: Determines the placement of this
// key in a sequence of keys that defines the order in which
// this node is traversed.
optional double sort_key_order = 23;
} }
message OnAccessibilityEventRequest { message OnAccessibilityEventRequest {
...@@ -102,6 +116,14 @@ message OnAccessibilityEventRequest { ...@@ -102,6 +116,14 @@ message OnAccessibilityEventRequest {
TEXT_SELECTION_CHANGED = 9; TEXT_SELECTION_CHANGED = 9;
CONTENT_CHANGED = 10; CONTENT_CHANGED = 10;
SCROLLED = 11; SCROLLED = 11;
ANNOUNCEMENT = 12;
}
enum TextDirection {
DEFAULT = 0;
// Left to right
LTR = 1;
// Right to left
RTL = 2;
} }
// Type of event this represents. // Type of event this represents.
optional EventType event_type = 1; optional EventType event_type = 1;
...@@ -111,6 +133,9 @@ message OnAccessibilityEventRequest { ...@@ -111,6 +133,9 @@ message OnAccessibilityEventRequest {
optional int32 window_id = 3; optional int32 window_id = 3;
// The 'flattened' semantic tree nodes. // The 'flattened' semantic tree nodes.
repeated SemanticsNode node_data = 4; repeated SemanticsNode node_data = 4;
// For announcements.
optional string text = 5;
optional TextDirection text_direction = 6;
} }
message OnAccessibilityEventResponse {} message OnAccessibilityEventResponse {}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment