MacViews: Get c/b/ui/views/tabs to build on Mac
[chromium-blink-merge.git] / chrome / browser / accessibility / accessibility_extension_api.cc
blob8cbc4d3bceb48aa1d4d084f915bddddd68d1f8f7
1 // Copyright (c) 2012 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/accessibility/accessibility_extension_api.h"
7 #include "base/json/json_writer.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/values.h"
10 #include "chrome/browser/accessibility/accessibility_extension_api_constants.h"
11 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
12 #include "chrome/browser/extensions/extension_service.h"
13 #include "chrome/browser/extensions/extension_tab_util.h"
14 #include "chrome/browser/infobars/infobar_service.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/common/extensions/api/accessibility_private.h"
17 #include "chrome/common/extensions/extension_constants.h"
18 #include "components/infobars/core/confirm_infobar_delegate.h"
19 #include "components/infobars/core/infobar.h"
20 #include "content/public/browser/browser_accessibility_state.h"
21 #include "extensions/browser/event_router.h"
22 #include "extensions/browser/extension_host.h"
23 #include "extensions/browser/extension_system.h"
24 #include "extensions/browser/lazy_background_task_queue.h"
25 #include "extensions/common/error_utils.h"
26 #include "extensions/common/manifest_handlers/background_info.h"
28 #if defined(OS_CHROMEOS)
29 #include "chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h"
30 #endif
32 namespace keys = extension_accessibility_api_constants;
33 namespace accessibility_private = extensions::api::accessibility_private;
35 // Returns the AccessibilityControlInfo serialized into a JSON string,
36 // consisting of an array of a single object of type AccessibilityObject,
37 // as defined in the accessibility extension api's json schema.
38 scoped_ptr<base::ListValue> ControlInfoToEventArguments(
39 const AccessibilityEventInfo* info) {
40 base::DictionaryValue* dict = new base::DictionaryValue();
41 info->SerializeToDict(dict);
43 scoped_ptr<base::ListValue> args(new base::ListValue());
44 args->Append(dict);
45 return args.Pass();
48 ExtensionAccessibilityEventRouter*
49 ExtensionAccessibilityEventRouter::GetInstance() {
50 return Singleton<ExtensionAccessibilityEventRouter>::get();
53 ExtensionAccessibilityEventRouter::ExtensionAccessibilityEventRouter()
54 : enabled_(false) {
57 ExtensionAccessibilityEventRouter::~ExtensionAccessibilityEventRouter() {
58 control_event_callback_.Reset();
61 void ExtensionAccessibilityEventRouter::SetAccessibilityEnabled(bool enabled) {
62 enabled_ = enabled;
65 bool ExtensionAccessibilityEventRouter::IsAccessibilityEnabled() const {
66 return enabled_;
69 void ExtensionAccessibilityEventRouter::SetControlEventCallbackForTesting(
70 ControlEventCallback control_event_callback) {
71 DCHECK(control_event_callback_.is_null());
72 control_event_callback_ = control_event_callback;
75 void ExtensionAccessibilityEventRouter::ClearControlEventCallback() {
76 control_event_callback_.Reset();
79 void ExtensionAccessibilityEventRouter::HandleWindowEvent(
80 ui::AXEvent event,
81 const AccessibilityWindowInfo* info) {
82 if (!control_event_callback_.is_null())
83 control_event_callback_.Run(event, info);
85 if (event == ui::AX_EVENT_ALERT)
86 OnWindowOpened(info);
89 void ExtensionAccessibilityEventRouter::HandleMenuEvent(
90 ui::AXEvent event,
91 const AccessibilityMenuInfo* info) {
92 switch (event) {
93 case ui::AX_EVENT_MENU_START:
94 case ui::AX_EVENT_MENU_POPUP_START:
95 OnMenuOpened(info);
96 break;
97 case ui::AX_EVENT_MENU_END:
98 case ui::AX_EVENT_MENU_POPUP_END:
99 OnMenuClosed(info);
100 break;
101 case ui::AX_EVENT_FOCUS:
102 OnControlFocused(info);
103 break;
104 case ui::AX_EVENT_HOVER:
105 OnControlHover(info);
106 break;
107 default:
108 NOTREACHED();
112 void ExtensionAccessibilityEventRouter::HandleControlEvent(
113 ui::AXEvent event,
114 const AccessibilityControlInfo* info) {
115 if (!control_event_callback_.is_null())
116 control_event_callback_.Run(event, info);
118 switch (event) {
119 case ui::AX_EVENT_TEXT_CHANGED:
120 case ui::AX_EVENT_TEXT_SELECTION_CHANGED:
121 OnTextChanged(info);
122 break;
123 case ui::AX_EVENT_VALUE_CHANGED:
124 case ui::AX_EVENT_ALERT:
125 OnControlAction(info);
126 break;
127 case ui::AX_EVENT_FOCUS:
128 OnControlFocused(info);
129 break;
130 case ui::AX_EVENT_HOVER:
131 OnControlHover(info);
132 break;
133 default:
134 NOTREACHED();
138 void ExtensionAccessibilityEventRouter::OnWindowOpened(
139 const AccessibilityWindowInfo* info) {
140 scoped_ptr<base::ListValue> args(ControlInfoToEventArguments(info));
141 DispatchEvent(info->profile(),
142 accessibility_private::OnWindowOpened::kEventName,
143 args.Pass());
146 void ExtensionAccessibilityEventRouter::OnControlFocused(
147 const AccessibilityControlInfo* info) {
148 last_focused_control_dict_.Clear();
149 info->SerializeToDict(&last_focused_control_dict_);
150 scoped_ptr<base::ListValue> args(ControlInfoToEventArguments(info));
151 DispatchEvent(info->profile(),
152 accessibility_private::OnControlFocused::kEventName,
153 args.Pass());
156 void ExtensionAccessibilityEventRouter::OnControlAction(
157 const AccessibilityControlInfo* info) {
158 scoped_ptr<base::ListValue> args(ControlInfoToEventArguments(info));
159 DispatchEvent(info->profile(),
160 accessibility_private::OnControlAction::kEventName,
161 args.Pass());
164 void ExtensionAccessibilityEventRouter::OnControlHover(
165 const AccessibilityControlInfo* info) {
166 scoped_ptr<base::ListValue> args(ControlInfoToEventArguments(info));
167 DispatchEvent(info->profile(),
168 accessibility_private::OnControlHover::kEventName,
169 args.Pass());
172 void ExtensionAccessibilityEventRouter::OnTextChanged(
173 const AccessibilityControlInfo* info) {
174 scoped_ptr<base::ListValue> args(ControlInfoToEventArguments(info));
175 DispatchEvent(info->profile(),
176 accessibility_private::OnTextChanged::kEventName,
177 args.Pass());
180 void ExtensionAccessibilityEventRouter::OnMenuOpened(
181 const AccessibilityMenuInfo* info) {
182 scoped_ptr<base::ListValue> args(ControlInfoToEventArguments(info));
183 DispatchEvent(info->profile(),
184 accessibility_private::OnMenuOpened::kEventName,
185 args.Pass());
188 void ExtensionAccessibilityEventRouter::OnMenuClosed(
189 const AccessibilityMenuInfo* info) {
190 scoped_ptr<base::ListValue> args(ControlInfoToEventArguments(info));
191 DispatchEvent(info->profile(),
192 accessibility_private::OnMenuClosed::kEventName,
193 args.Pass());
196 void ExtensionAccessibilityEventRouter::OnChromeVoxLoadStateChanged(
197 Profile* profile,
198 bool loading,
199 bool make_announcements) {
200 scoped_ptr<base::ListValue> event_args(new base::ListValue());
201 event_args->AppendBoolean(loading);
202 event_args->AppendBoolean(make_announcements);
203 ExtensionAccessibilityEventRouter::DispatchEventToChromeVox(
204 profile,
205 accessibility_private::OnChromeVoxLoadStateChanged::kEventName,
206 event_args.Pass());
209 // Static.
210 void ExtensionAccessibilityEventRouter::DispatchEventToChromeVox(
211 Profile* profile,
212 const char* event_name,
213 scoped_ptr<base::ListValue> event_args) {
214 extensions::ExtensionSystem* system =
215 extensions::ExtensionSystem::Get(profile);
216 if (!system)
217 return;
218 scoped_ptr<extensions::Event> event(new extensions::Event(event_name,
219 event_args.Pass()));
220 system->event_router()->DispatchEventWithLazyListener(
221 extension_misc::kChromeVoxExtensionId, event.Pass());
224 void ExtensionAccessibilityEventRouter::DispatchEvent(
225 Profile* profile,
226 const char* event_name,
227 scoped_ptr<base::ListValue> event_args) {
228 if (!enabled_ || !profile)
229 return;
230 extensions::EventRouter* event_router = extensions::EventRouter::Get(profile);
231 if (!event_router)
232 return;
234 scoped_ptr<extensions::Event> event(new extensions::Event(
235 event_name, event_args.Pass()));
236 event_router->BroadcastEvent(event.Pass());
239 bool AccessibilityPrivateSetAccessibilityEnabledFunction::RunSync() {
240 bool enabled;
241 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(0, &enabled));
242 ExtensionAccessibilityEventRouter::GetInstance()
243 ->SetAccessibilityEnabled(enabled);
244 return true;
247 bool AccessibilityPrivateSetNativeAccessibilityEnabledFunction::RunSync() {
248 bool enabled;
249 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(0, &enabled));
250 if (enabled) {
251 content::BrowserAccessibilityState::GetInstance()->
252 EnableAccessibility();
253 } else {
254 content::BrowserAccessibilityState::GetInstance()->
255 DisableAccessibility();
257 return true;
260 bool AccessibilityPrivateGetFocusedControlFunction::RunSync() {
261 // Get the serialized dict from the last focused control and return it.
262 // However, if the dict is empty, that means we haven't seen any focus
263 // events yet, so return null instead.
264 ExtensionAccessibilityEventRouter *accessibility_event_router =
265 ExtensionAccessibilityEventRouter::GetInstance();
266 base::DictionaryValue *last_focused_control_dict =
267 accessibility_event_router->last_focused_control_dict();
268 if (last_focused_control_dict->size()) {
269 SetResult(last_focused_control_dict->DeepCopyWithoutEmptyChildren());
270 } else {
271 SetResult(base::Value::CreateNullValue());
273 return true;
276 bool AccessibilityPrivateGetAlertsForTabFunction::RunSync() {
277 int tab_id;
278 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
280 TabStripModel* tab_strip = NULL;
281 content::WebContents* contents = NULL;
282 int tab_index = -1;
283 if (!extensions::ExtensionTabUtil::GetTabById(tab_id,
284 GetProfile(),
285 include_incognito(),
286 NULL,
287 &tab_strip,
288 &contents,
289 &tab_index)) {
290 error_ = extensions::ErrorUtils::FormatErrorMessage(
291 extensions::tabs_constants::kTabNotFoundError,
292 base::IntToString(tab_id));
293 return false;
296 base::ListValue* alerts_value = new base::ListValue;
298 InfoBarService* infobar_service = InfoBarService::FromWebContents(contents);
299 for (size_t i = 0; i < infobar_service->infobar_count(); ++i) {
300 // TODO(hashimoto): Make other kind of alerts available. crosbug.com/24281
301 ConfirmInfoBarDelegate* confirm_infobar_delegate =
302 infobar_service->infobar_at(i)->delegate()->AsConfirmInfoBarDelegate();
303 if (confirm_infobar_delegate) {
304 base::DictionaryValue* alert_value = new base::DictionaryValue;
305 const base::string16 message_text =
306 confirm_infobar_delegate->GetMessageText();
307 alert_value->SetString(keys::kMessageKey, message_text);
308 alerts_value->Append(alert_value);
312 SetResult(alerts_value);
313 return true;
316 bool AccessibilityPrivateSetFocusRingFunction::RunSync() {
317 #if defined(OS_CHROMEOS)
318 base::ListValue* rect_values = NULL;
319 EXTENSION_FUNCTION_VALIDATE(args_->GetList(0, &rect_values));
321 std::vector<gfx::Rect> rects;
322 for (size_t i = 0; i < rect_values->GetSize(); ++i) {
323 base::DictionaryValue* rect_value = NULL;
324 EXTENSION_FUNCTION_VALIDATE(rect_values->GetDictionary(i, &rect_value));
325 int left, top, width, height;
326 EXTENSION_FUNCTION_VALIDATE(rect_value->GetInteger(keys::kLeft, &left));
327 EXTENSION_FUNCTION_VALIDATE(rect_value->GetInteger(keys::kTop, &top));
328 EXTENSION_FUNCTION_VALIDATE(rect_value->GetInteger(keys::kWidth, &width));
329 EXTENSION_FUNCTION_VALIDATE(rect_value->GetInteger(keys::kHeight, &height));
330 rects.push_back(gfx::Rect(left, top, width, height));
333 chromeos::AccessibilityFocusRingController::GetInstance()->SetFocusRing(
334 rects);
335 return true;
336 #endif // defined(OS_CHROMEOS)
338 error_ = keys:: kErrorNotSupported;
339 return false;