1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
11 #include "base/stl_util.h"
12 #include "base/values.h"
13 #include "chrome/common/extensions/api/automation_internal.h"
14 #include "chrome/common/extensions/chrome_extension_messages.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/notification_source.h"
17 #include "content/public/browser/notification_types.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "extensions/browser/event_router.h"
20 #include "ui/accessibility/ax_enums.h"
21 #include "ui/accessibility/ax_node_data.h"
23 namespace extensions
{
26 AutomationEventRouter
* AutomationEventRouter::GetInstance() {
27 return Singleton
<AutomationEventRouter
,
28 LeakySingletonTraits
<AutomationEventRouter
>>::get();
31 AutomationEventRouter::AutomationEventRouter() {
32 registrar_
.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED
,
33 content::NotificationService::AllBrowserContextsAndSources());
34 registrar_
.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED
,
35 content::NotificationService::AllBrowserContextsAndSources());
38 AutomationEventRouter::~AutomationEventRouter() {
41 void AutomationEventRouter::RegisterListenerForOneTree(
42 int listener_process_id
,
43 int listener_routing_id
,
44 int source_ax_tree_id
) {
45 Register(listener_process_id
, listener_routing_id
, source_ax_tree_id
, false);
48 void AutomationEventRouter::RegisterListenerWithDesktopPermission(
49 int listener_process_id
,
50 int listener_routing_id
) {
51 Register(listener_process_id
, listener_routing_id
, 0, true);
54 void AutomationEventRouter::DispatchAccessibilityEvent(
55 const ExtensionMsg_AccessibilityEventParams
& params
) {
56 for (const auto& listener
: listeners_
) {
57 if (!listener
.desktop
&&
58 listener
.tree_ids
.find(params
.tree_id
) == listener
.tree_ids
.end()) {
62 content::RenderProcessHost
* rph
=
63 content::RenderProcessHost::FromID(listener
.process_id
);
64 rph
->Send(new ExtensionMsg_AccessibilityEvent(listener
.routing_id
,
69 void AutomationEventRouter::DispatchTreeDestroyedEvent(
71 content::BrowserContext
* browser_context
) {
72 scoped_ptr
<base::ListValue
> args(
73 api::automation_internal::OnAccessibilityTreeDestroyed::Create(tree_id
));
74 scoped_ptr
<Event
> event(new Event(
75 events::AUTOMATION_INTERNAL_ON_ACCESSIBILITY_TREE_DESTROYED
,
76 api::automation_internal::OnAccessibilityTreeDestroyed::kEventName
,
78 event
->restrict_to_browser_context
= browser_context
;
79 EventRouter::Get(browser_context
)->BroadcastEvent(event
.Pass());
82 AutomationEventRouter::AutomationListener::AutomationListener() {
85 AutomationEventRouter::AutomationListener::~AutomationListener() {
88 void AutomationEventRouter::Register(
89 int listener_process_id
,
90 int listener_routing_id
,
93 auto iter
= std::find_if(
96 [listener_process_id
, listener_routing_id
](
97 const AutomationListener
& item
) {
98 return (item
.process_id
== listener_process_id
&&
99 item
.routing_id
== listener_routing_id
);
102 // Add a new entry if we don't have one with that process and routing id.
103 if (iter
== listeners_
.end()) {
104 AutomationListener listener
;
105 listener
.routing_id
= listener_routing_id
;
106 listener
.process_id
= listener_process_id
;
107 listener
.desktop
= desktop
;
108 listener
.tree_ids
.insert(ax_tree_id
);
109 listeners_
.push_back(listener
);
113 // We have an entry with that process and routing id, so update the set of
114 // tree ids it wants to listen to, and update its desktop permission.
115 iter
->tree_ids
.insert(ax_tree_id
);
117 iter
->desktop
= true;
120 void AutomationEventRouter::Observe(
122 const content::NotificationSource
& source
,
123 const content::NotificationDetails
& details
) {
124 if (type
!= content::NOTIFICATION_RENDERER_PROCESS_TERMINATED
&&
125 type
!= content::NOTIFICATION_RENDERER_PROCESS_CLOSED
) {
130 content::RenderProcessHost
* rph
=
131 content::Source
<content::RenderProcessHost
>(source
).ptr();
132 int process_id
= rph
->GetID();
137 [process_id
](const AutomationListener
& item
) {
138 return item
.process_id
== process_id
;
143 } // namespace extensions