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"
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());
48 ExtensionAccessibilityEventRouter
*
49 ExtensionAccessibilityEventRouter::GetInstance() {
50 return Singleton
<ExtensionAccessibilityEventRouter
>::get();
53 ExtensionAccessibilityEventRouter::ExtensionAccessibilityEventRouter()
57 ExtensionAccessibilityEventRouter::~ExtensionAccessibilityEventRouter() {
58 control_event_callback_
.Reset();
61 void ExtensionAccessibilityEventRouter::SetAccessibilityEnabled(bool enabled
) {
65 bool ExtensionAccessibilityEventRouter::IsAccessibilityEnabled() const {
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(
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
)
89 void ExtensionAccessibilityEventRouter::HandleMenuEvent(
91 const AccessibilityMenuInfo
* info
) {
93 case ui::AX_EVENT_MENU_START
:
94 case ui::AX_EVENT_MENU_POPUP_START
:
97 case ui::AX_EVENT_MENU_END
:
98 case ui::AX_EVENT_MENU_POPUP_END
:
101 case ui::AX_EVENT_FOCUS
:
102 OnControlFocused(info
);
104 case ui::AX_EVENT_HOVER
:
105 OnControlHover(info
);
112 void ExtensionAccessibilityEventRouter::HandleControlEvent(
114 const AccessibilityControlInfo
* info
) {
115 if (!control_event_callback_
.is_null())
116 control_event_callback_
.Run(event
, info
);
119 case ui::AX_EVENT_TEXT_CHANGED
:
120 case ui::AX_EVENT_TEXT_SELECTION_CHANGED
:
123 case ui::AX_EVENT_VALUE_CHANGED
:
124 case ui::AX_EVENT_ALERT
:
125 OnControlAction(info
);
127 case ui::AX_EVENT_FOCUS
:
128 OnControlFocused(info
);
130 case ui::AX_EVENT_HOVER
:
131 OnControlHover(info
);
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
,
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
,
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
,
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
,
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
,
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
,
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
,
196 void ExtensionAccessibilityEventRouter::OnChromeVoxLoadStateChanged(
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(
205 accessibility_private::OnChromeVoxLoadStateChanged::kEventName
,
210 void ExtensionAccessibilityEventRouter::DispatchEventToChromeVox(
212 const char* event_name
,
213 scoped_ptr
<base::ListValue
> event_args
) {
214 extensions::ExtensionSystem
* system
=
215 extensions::ExtensionSystem::Get(profile
);
218 scoped_ptr
<extensions::Event
> event(new extensions::Event(event_name
,
220 system
->event_router()->DispatchEventWithLazyListener(
221 extension_misc::kChromeVoxExtensionId
, event
.Pass());
224 void ExtensionAccessibilityEventRouter::DispatchEvent(
226 const char* event_name
,
227 scoped_ptr
<base::ListValue
> event_args
) {
228 if (!enabled_
|| !profile
)
230 extensions::EventRouter
* event_router
= extensions::EventRouter::Get(profile
);
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() {
241 EXTENSION_FUNCTION_VALIDATE(args_
->GetBoolean(0, &enabled
));
242 ExtensionAccessibilityEventRouter::GetInstance()
243 ->SetAccessibilityEnabled(enabled
);
247 bool AccessibilityPrivateSetNativeAccessibilityEnabledFunction::RunSync() {
249 EXTENSION_FUNCTION_VALIDATE(args_
->GetBoolean(0, &enabled
));
251 content::BrowserAccessibilityState::GetInstance()->
252 EnableAccessibility();
254 content::BrowserAccessibilityState::GetInstance()->
255 DisableAccessibility();
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());
271 SetResult(base::Value::CreateNullValue());
276 bool AccessibilityPrivateGetAlertsForTabFunction::RunSync() {
278 EXTENSION_FUNCTION_VALIDATE(args_
->GetInteger(0, &tab_id
));
280 TabStripModel
* tab_strip
= NULL
;
281 content::WebContents
* contents
= NULL
;
283 if (!extensions::ExtensionTabUtil::GetTabById(tab_id
,
290 error_
= extensions::ErrorUtils::FormatErrorMessage(
291 extensions::tabs_constants::kTabNotFoundError
,
292 base::IntToString(tab_id
));
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
);
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(
336 #endif // defined(OS_CHROMEOS)
338 error_
= keys:: kErrorNotSupported
;