1 // Copyright (c) 2011 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.
4
5 #include "chrome/browser/extensions/extension_tabs_module.h"
6
7 #include "base/json/json_writer.h"
8 #include "base/stl_util-inl.h"
9 #include "base/string_util.h"
10 #include "base/values.h"
11 #include "chrome/browser/extensions/extension_accessibility_api.h"
12 #include "chrome/browser/extensions/extension_accessibility_api_constants.h"
13 #include "chrome/browser/extensions/extension_event_router.h"
14 #include "chrome/browser/extensions/extension_function_dispatcher.h"
15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/browser_list.h"
18 #include "chrome/browser/ui/browser_window.h"
19 #include "chrome/common/extensions/extension.h"
20 #include "content/common/notification_service.h"
21
22 namespace keys = extension_accessibility_api_constants;
23
24 // Returns the AccessibilityControlInfo serialized into a JSON string,
25 // consisting of an array of a single object of type AccessibilityObject,
26 // as defined in the accessibility extension api's json schema.
ControlInfoToJsonString(const AccessibilityControlInfo * info)27 std::string ControlInfoToJsonString(const AccessibilityControlInfo* info) {
28 ListValue args;
29 DictionaryValue* dict = new DictionaryValue();
30 info->SerializeToDict(dict);
31 args.Append(dict);
32 std::string json_args;
33 base::JSONWriter::Write(&args, false, &json_args);
34 return json_args;
35 }
36
37 ExtensionAccessibilityEventRouter*
GetInstance()38 ExtensionAccessibilityEventRouter::GetInstance() {
39 return Singleton<ExtensionAccessibilityEventRouter>::get();
40 }
41
ExtensionAccessibilityEventRouter()42 ExtensionAccessibilityEventRouter::ExtensionAccessibilityEventRouter()
43 : enabled_(false) {}
44
~ExtensionAccessibilityEventRouter()45 ExtensionAccessibilityEventRouter::~ExtensionAccessibilityEventRouter() {
46 STLDeleteElements(&on_enabled_listeners_);
47 STLDeleteElements(&on_disabled_listeners_);
48 }
49
ObserveProfile(Profile * profile)50 void ExtensionAccessibilityEventRouter::ObserveProfile(Profile* profile) {
51 last_focused_control_dict_.Clear();
52
53 if (registrar_.IsEmpty()) {
54 registrar_.Add(this,
55 NotificationType::ACCESSIBILITY_WINDOW_OPENED,
56 NotificationService::AllSources());
57 registrar_.Add(this,
58 NotificationType::ACCESSIBILITY_WINDOW_CLOSED,
59 NotificationService::AllSources());
60 registrar_.Add(this,
61 NotificationType::ACCESSIBILITY_CONTROL_FOCUSED,
62 NotificationService::AllSources());
63 registrar_.Add(this,
64 NotificationType::ACCESSIBILITY_CONTROL_ACTION,
65 NotificationService::AllSources());
66 registrar_.Add(this,
67 NotificationType::ACCESSIBILITY_TEXT_CHANGED,
68 NotificationService::AllSources());
69 registrar_.Add(this,
70 NotificationType::ACCESSIBILITY_MENU_OPENED,
71 NotificationService::AllSources());
72 registrar_.Add(this,
73 NotificationType::ACCESSIBILITY_MENU_CLOSED,
74 NotificationService::AllSources());
75 }
76 }
77
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)78 void ExtensionAccessibilityEventRouter::Observe(
79 NotificationType type,
80 const NotificationSource& source,
81 const NotificationDetails& details) {
82 switch (type.value) {
83 case NotificationType::ACCESSIBILITY_WINDOW_OPENED:
84 OnWindowOpened(Details<const AccessibilityWindowInfo>(details).ptr());
85 break;
86 case NotificationType::ACCESSIBILITY_WINDOW_CLOSED:
87 OnWindowClosed(Details<const AccessibilityWindowInfo>(details).ptr());
88 break;
89 case NotificationType::ACCESSIBILITY_CONTROL_FOCUSED:
90 OnControlFocused(Details<const AccessibilityControlInfo>(details).ptr());
91 break;
92 case NotificationType::ACCESSIBILITY_CONTROL_ACTION:
93 OnControlAction(Details<const AccessibilityControlInfo>(details).ptr());
94 break;
95 case NotificationType::ACCESSIBILITY_TEXT_CHANGED:
96 OnTextChanged(Details<const AccessibilityControlInfo>(details).ptr());
97 break;
98 case NotificationType::ACCESSIBILITY_MENU_OPENED:
99 OnMenuOpened(Details<const AccessibilityMenuInfo>(details).ptr());
100 break;
101 case NotificationType::ACCESSIBILITY_MENU_CLOSED:
102 OnMenuClosed(Details<const AccessibilityMenuInfo>(details).ptr());
103 break;
104 default:
105 NOTREACHED();
106 }
107 }
108
SetAccessibilityEnabled(bool enabled)109 void ExtensionAccessibilityEventRouter::SetAccessibilityEnabled(bool enabled) {
110 if (enabled_ != enabled) {
111 enabled_ = enabled;
112 if (enabled_) {
113 for (unsigned int i = 0; i < on_enabled_listeners_.size(); i++) {
114 on_enabled_listeners_[i]->Run();
115 }
116 } else {
117 for (unsigned int i = 0; i < on_disabled_listeners_.size(); i++) {
118 on_disabled_listeners_[i]->Run();
119 }
120 }
121 }
122 }
123
IsAccessibilityEnabled() const124 bool ExtensionAccessibilityEventRouter::IsAccessibilityEnabled() const {
125 return enabled_;
126 }
127
AddOnEnabledListener(Callback * callback)128 void ExtensionAccessibilityEventRouter::AddOnEnabledListener(
129 Callback* callback) {
130 on_enabled_listeners_.push_back(callback);
131 }
132
AddOnDisabledListener(Callback * callback)133 void ExtensionAccessibilityEventRouter::AddOnDisabledListener(
134 Callback* callback) {
135 on_disabled_listeners_.push_back(callback);
136 }
137
OnWindowOpened(const AccessibilityWindowInfo * info)138 void ExtensionAccessibilityEventRouter::OnWindowOpened(
139 const AccessibilityWindowInfo* info) {
140 std::string json_args = ControlInfoToJsonString(info);
141 DispatchEvent(info->profile(), keys::kOnWindowOpened, json_args);
142 }
143
OnWindowClosed(const AccessibilityWindowInfo * info)144 void ExtensionAccessibilityEventRouter::OnWindowClosed(
145 const AccessibilityWindowInfo* info) {
146 std::string json_args = ControlInfoToJsonString(info);
147 DispatchEvent(info->profile(), keys::kOnWindowClosed, json_args);
148 }
149
OnControlFocused(const AccessibilityControlInfo * info)150 void ExtensionAccessibilityEventRouter::OnControlFocused(
151 const AccessibilityControlInfo* info) {
152 last_focused_control_dict_.Clear();
153 info->SerializeToDict(&last_focused_control_dict_);
154 std::string json_args = ControlInfoToJsonString(info);
155 DispatchEvent(info->profile(), keys::kOnControlFocused, json_args);
156 }
157
OnControlAction(const AccessibilityControlInfo * info)158 void ExtensionAccessibilityEventRouter::OnControlAction(
159 const AccessibilityControlInfo* info) {
160 std::string json_args = ControlInfoToJsonString(info);
161 DispatchEvent(info->profile(), keys::kOnControlAction, json_args);
162 }
163
OnTextChanged(const AccessibilityControlInfo * info)164 void ExtensionAccessibilityEventRouter::OnTextChanged(
165 const AccessibilityControlInfo* info) {
166 std::string json_args = ControlInfoToJsonString(info);
167 DispatchEvent(info->profile(), keys::kOnTextChanged, json_args);
168 }
169
OnMenuOpened(const AccessibilityMenuInfo * info)170 void ExtensionAccessibilityEventRouter::OnMenuOpened(
171 const AccessibilityMenuInfo* info) {
172 std::string json_args = ControlInfoToJsonString(info);
173 DispatchEvent(info->profile(), keys::kOnMenuOpened, json_args);
174 }
175
OnMenuClosed(const AccessibilityMenuInfo * info)176 void ExtensionAccessibilityEventRouter::OnMenuClosed(
177 const AccessibilityMenuInfo* info) {
178 std::string json_args = ControlInfoToJsonString(info);
179 DispatchEvent(info->profile(), keys::kOnMenuClosed, json_args);
180 }
181
DispatchEvent(Profile * profile,const char * event_name,const std::string & json_args)182 void ExtensionAccessibilityEventRouter::DispatchEvent(
183 Profile* profile,
184 const char* event_name,
185 const std::string& json_args) {
186 if (enabled_ && profile && profile->GetExtensionEventRouter()) {
187 profile->GetExtensionEventRouter()->DispatchEventToRenderers(
188 event_name, json_args, NULL, GURL());
189 }
190 }
191
RunImpl()192 bool SetAccessibilityEnabledFunction::RunImpl() {
193 bool enabled;
194 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(0, &enabled));
195 ExtensionAccessibilityEventRouter::GetInstance()
196 ->SetAccessibilityEnabled(enabled);
197 return true;
198 }
199
RunImpl()200 bool GetFocusedControlFunction::RunImpl() {
201 // Get the serialized dict from the last focused control and return it.
202 // However, if the dict is empty, that means we haven't seen any focus
203 // events yet, so return null instead.
204 ExtensionAccessibilityEventRouter *accessibility_event_router =
205 ExtensionAccessibilityEventRouter::GetInstance();
206 DictionaryValue *last_focused_control_dict =
207 accessibility_event_router->last_focused_control_dict();
208 if (last_focused_control_dict->size()) {
209 result_.reset(last_focused_control_dict->DeepCopyWithoutEmptyChildren());
210 } else {
211 result_.reset(Value::CreateNullValue());
212 }
213 return true;
214 }
215