Commit 9760426c authored by James Cook's avatar James Cook Committed by Commit Bot

Add ui::AXEventBundleSink interface for accessibility

This breaks a dependency from AutomationManagerAura to the extensions
system. It should make AutomationManagerAura easier to test in unit
tests.

Bug: 910280
Test: browser_tests
Change-Id: I3e7036671d6e6140b6e19b72e7d6482e2fb6f376
Reviewed-on: https://chromium-review.googlesource.com/c/1357548Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Commit-Queue: James Cook <jamescook@chromium.org>
Cr-Commit-Position: refs/heads/master@{#613347}
parent 391671c4
......@@ -26,6 +26,10 @@
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#if defined(USE_AURA)
#include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
#endif
namespace extensions {
// static
......@@ -41,6 +45,10 @@ AutomationEventRouter::AutomationEventRouter()
content::NotificationService::AllBrowserContextsAndSources());
registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
content::NotificationService::AllBrowserContextsAndSources());
#if defined(USE_AURA)
// Not reset because |this| is leaked.
AutomationManagerAura::GetInstance()->set_event_bundle_sink(this);
#endif
}
AutomationEventRouter::~AutomationEventRouter() {
......@@ -208,6 +216,20 @@ void AutomationEventRouter::Register(const ExtensionId& extension_id,
iter->desktop = true;
}
void AutomationEventRouter::DispatchAccessibilityEvents(
const ui::AXTreeID& tree_id,
std::vector<ui::AXTreeUpdate> updates,
const gfx::Point& mouse_location,
std::vector<ui::AXEvent> events) {
ExtensionMsg_AccessibilityEventBundleParams event_bundle;
event_bundle.tree_id = tree_id;
event_bundle.updates = std::move(updates);
event_bundle.mouse_location = mouse_location;
event_bundle.events = std::move(events);
DispatchAccessibilityEvents(event_bundle);
}
void AutomationEventRouter::Observe(
int type,
const content::NotificationSource& source,
......
......@@ -17,6 +17,7 @@
#include "content/public/browser/notification_registrar.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/extension_messages.h"
#include "ui/accessibility/ax_event_bundle_sink.h"
#include "ui/accessibility/ax_tree_id.h"
class Profile;
......@@ -35,7 +36,8 @@ struct ExtensionMsg_AccessibilityLocationChangeParams;
namespace extensions {
struct AutomationListener;
class AutomationEventRouter : public content::NotificationObserver {
class AutomationEventRouter : public ui::AXEventBundleSink,
public content::NotificationObserver {
public:
static AutomationEventRouter* GetInstance();
......@@ -95,6 +97,12 @@ class AutomationEventRouter : public content::NotificationObserver {
ui::AXTreeID source_ax_tree_id,
bool desktop);
// ui::AXEventBundleSink:
void DispatchAccessibilityEvents(const ui::AXTreeID& tree_id,
std::vector<ui::AXTreeUpdate> updates,
const gfx::Point& mouse_location,
std::vector<ui::AXEvent> events) override;
// content::NotificationObserver interface.
void Observe(int type,
const content::NotificationSource& source,
......
......@@ -8,13 +8,12 @@
#include "base/memory/singleton.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
#include "chrome/common/extensions/chrome_extension_messages.h"
#include "content/public/browser/render_frame_host.h"
#include "extensions/common/extension_messages.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/accessibility/ax_enum_util.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/ax_event.h"
#include "ui/accessibility/ax_event_bundle_sink.h"
#include "ui/accessibility/ax_tree_id_registry.h"
#include "ui/accessibility/platform/aura_window_properties.h"
#include "ui/aura/env.h"
......@@ -33,8 +32,6 @@
#include "ui/base/ui_base_features.h"
#endif
using extensions::AutomationEventRouter;
// static
AutomationManagerAura* AutomationManagerAura::GetInstance() {
return base::Singleton<AutomationManagerAura>::get();
......@@ -198,16 +195,13 @@ void AutomationManagerAura::SendEvent(views::AXAuraObjWrapper* aura_obj,
}
processing_events_ = true;
ExtensionMsg_AccessibilityEventBundleParams event_bundle;
event_bundle.tree_id = ui::DesktopAXTreeID();
event_bundle.mouse_location = aura::Env::GetInstance()->last_mouse_location();
std::vector<ui::AXTreeUpdate> tree_updates;
ui::AXTreeUpdate update;
if (!current_tree_serializer_->SerializeChanges(aura_obj, &update)) {
LOG(ERROR) << "Unable to serialize one accessibility event.";
return;
}
event_bundle.updates.push_back(update);
tree_updates.push_back(update);
// Make sure the focused node is serialized.
views::AXAuraObjWrapper* focus =
......@@ -215,9 +209,10 @@ void AutomationManagerAura::SendEvent(views::AXAuraObjWrapper* aura_obj,
if (focus) {
ui::AXTreeUpdate focused_node_update;
current_tree_serializer_->SerializeChanges(focus, &focused_node_update);
event_bundle.updates.push_back(focused_node_update);
tree_updates.push_back(focused_node_update);
}
std::vector<ui::AXEvent> events;
// Fire the event on the node, but only if it's actually in the tree.
// Sometimes we get events fired on nodes with an ancestor that's
// marked invisible, for example. In those cases we should still
......@@ -227,14 +222,14 @@ void AutomationManagerAura::SendEvent(views::AXAuraObjWrapper* aura_obj,
ui::AXEvent event;
event.id = aura_obj->GetUniqueId();
event.event_type = event_type;
event_bundle.events.push_back(event);
events.push_back(event);
}
AutomationEventRouter* router = AutomationEventRouter::GetInstance();
router->DispatchAccessibilityEvents(event_bundle);
if (event_bundle_callback_for_testing_)
event_bundle_callback_for_testing_.Run(event_bundle);
if (event_bundle_sink_) {
event_bundle_sink_->DispatchAccessibilityEvents(
ui::DesktopAXTreeID(), std::move(tree_updates),
aura::Env::GetInstance()->last_mouse_location(), std::move(events));
}
processing_events_ = false;
auto pending_events_copy = pending_events_;
......
......@@ -27,6 +27,10 @@ template <typename T>
struct DefaultSingletonTraits;
} // namespace base
namespace ui {
class AXEventBundleSink;
}
namespace views {
class AXAuraObjWrapper;
class View;
......@@ -35,8 +39,6 @@ class View;
using AuraAXTreeSerializer = ui::
AXTreeSerializer<views::AXAuraObjWrapper*, ui::AXNodeData, ui::AXTreeData>;
struct ExtensionMsg_AccessibilityEventBundleParams;
// Manages a tree of automation nodes.
class AutomationManagerAura : public ui::AXHostDelegate,
public views::AXAuraObjCache::Delegate,
......@@ -67,10 +69,8 @@ class AutomationManagerAura : public ui::AXHostDelegate,
// views::AXEventObserver:
void OnViewEvent(views::View* view, ax::mojom::Event event_type) override;
void set_event_bundle_callback_for_testing(
base::RepeatingCallback<void(ExtensionMsg_AccessibilityEventBundleParams)>
callback) {
event_bundle_callback_for_testing_ = callback;
void set_event_bundle_sink(ui::AXEventBundleSink* sink) {
event_bundle_sink_ = sink;
}
protected:
......@@ -113,8 +113,9 @@ class AutomationManagerAura : public ui::AXHostDelegate,
std::vector<std::pair<views::AXAuraObjWrapper*, ax::mojom::Event>>
pending_events_;
base::RepeatingCallback<void(ExtensionMsg_AccessibilityEventBundleParams)>
event_bundle_callback_for_testing_;
// The handler for AXEvents (e.g. the extensions subsystem in production, or
// a fake for tests).
ui::AXEventBundleSink* event_bundle_sink_ = nullptr;
base::WeakPtrFactory<AutomationManagerAura> weak_ptr_factory_;
......
......@@ -6,7 +6,6 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/extensions/chrome_extension_messages.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chrome/test/views/accessibility_checker.h"
......@@ -15,6 +14,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "extensions/common/extension_messages.h"
#include "ui/accessibility/ax_event_bundle_sink.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
#include "ui/views/accessibility/ax_tree_source_views.h"
......@@ -47,16 +47,19 @@ void FindAllHostsOfWebContentsWithAXTreeID(
}
}
// A class that installs a test-only callback to handle automation events
// A class that installs itself as the sink to handle automation event bundles
// from AutomationManagerAura, then waits until an automation event indicates
// that a given node ID is focused.
class AutomationEventWaiter {
class AutomationEventWaiter : public ui::AXEventBundleSink {
public:
explicit AutomationEventWaiter(AutomationManagerAura* manager)
: run_loop_(std::make_unique<base::RunLoop>()), weak_factory_(this) {
manager->set_event_bundle_callback_for_testing(
base::BindRepeating(&AutomationEventWaiter::EventBundleCallback,
weak_factory_.GetWeakPtr()));
AutomationEventWaiter() : run_loop_(std::make_unique<base::RunLoop>()) {
AutomationManagerAura::GetInstance()->set_event_bundle_sink(this);
}
~AutomationEventWaiter() override {
// Don't bother to reconnect to AutomationEventRouter because it's not
// relevant to the tests.
AutomationManagerAura::GetInstance()->set_event_bundle_sink(nullptr);
}
// Returns immediately if the node with AXAuraObjCache ID |node_id|
......@@ -79,11 +82,13 @@ class AutomationEventWaiter {
}
private:
// Callback to intercept messages sent by AutomationManagerAura.
void EventBundleCallback(
ExtensionMsg_AccessibilityEventBundleParams event_bundle) {
for (size_t i = 0; i < event_bundle.updates.size(); ++i) {
int focused_node_id = event_bundle.updates[i].tree_data.focus_id;
// ui::AXEventBundleSink:
void DispatchAccessibilityEvents(const ui::AXTreeID& tree_id,
std::vector<ui::AXTreeUpdate> updates,
const gfx::Point& mouse_location,
std::vector<ui::AXEvent> events) override {
for (const ui::AXTreeUpdate& update : updates) {
int focused_node_id = update.tree_data.focus_id;
focused_node_ids_.push_back(focused_node_id);
if (focused_node_id == node_id_to_wait_for_)
run_loop_->QuitClosure().Run();
......@@ -93,7 +98,6 @@ class AutomationEventWaiter {
std::unique_ptr<base::RunLoop> run_loop_;
int node_id_to_wait_for_ = 0;
std::vector<int> focused_node_ids_;
base::WeakPtrFactory<AutomationEventWaiter> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(AutomationEventWaiter);
};
......@@ -174,7 +178,7 @@ IN_PROC_BROWSER_TEST_F(AutomationManagerAuraBrowserTest,
widget->GetRootView()->AddChildView(view3);
views::AXAuraObjWrapper* wrapper3 = cache->GetOrCreate(view3);
AutomationEventWaiter waiter(manager);
AutomationEventWaiter waiter;
// Focus view1, then block until we get an accessibility event that
// shows this view is focused.
......
......@@ -2,9 +2,9 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/config/linux/pkg_config.gni")
import("//build/config/features.gni")
import("//build/config/jumbo.gni")
import("//build/config/linux/pkg_config.gni")
import("//build/config/ui.gni")
import("//mojo/public/tools/bindings/mojom.gni")
import("//services/service_manager/public/service_manifest.gni")
......@@ -39,6 +39,7 @@ jumbo_component("accessibility") {
"ax_enum_util.h",
"ax_event.cc",
"ax_event.h",
"ax_event_bundle_sink.h",
"ax_event_generator.cc",
"ax_event_generator.h",
"ax_export.h",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_ACCESSIBILITY_AX_EVENT_BUNDLE_SINK_H_
#define UI_ACCESSIBILITY_AX_EVENT_BUNDLE_SINK_H_
#include <vector>
#include "ui/accessibility/ax_export.h"
#include "ui/accessibility/ax_tree_update.h"
namespace gfx {
class Point;
}
namespace ui {
struct AXEvent;
class AXTreeID;
// Interface for a consumer of groups of AXEvents.
class AX_EXPORT AXEventBundleSink {
public:
// |tree_id|: ID of the accessibility tree that the events apply to.
// |updates|: Zero or more updates to the accessibility tree to apply first.
// |mouse location|: Current mouse location in screen coordinates.
// |events|: Zero or more events to fire after the updates have been applied.
// Callers may wish to std::move() into the vector params to avoid copies.
virtual void DispatchAccessibilityEvents(const AXTreeID& tree_id,
std::vector<AXTreeUpdate> updates,
const gfx::Point& mouse_location,
std::vector<AXEvent> events) = 0;
protected:
virtual ~AXEventBundleSink() {}
};
} // namespace ui
#endif // UI_ACCESSIBILITY_AX_EVENT_BUNDLE_SINK_H_
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