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/confirm_infobar_delegate.h"
15 #include "chrome/browser/infobars/infobar_service.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/common/extensions/api/experimental_accessibility.h"
18 #include "components/infobars/core/infobar.h"
19 #include "content/public/browser/browser_accessibility_state.h"
20 #include "extensions/browser/event_router.h"
21 #include "extensions/browser/extension_host.h"
22 #include "extensions/browser/extension_system.h"
23 #include "extensions/browser/lazy_background_task_queue.h"
24 #include "extensions/common/error_utils.h"
25 #include "extensions/common/manifest_handlers/background_info.h"
27 namespace keys
= extension_accessibility_api_constants
;
28 namespace experimental_accessibility
=
29 extensions::api::experimental_accessibility
;
31 // Returns the AccessibilityControlInfo serialized into a JSON string,
32 // consisting of an array of a single object of type AccessibilityObject,
33 // as defined in the accessibility extension api's json schema.
34 scoped_ptr
<base::ListValue
> ControlInfoToEventArguments(
35 const AccessibilityEventInfo
* info
) {
36 base::DictionaryValue
* dict
= new base::DictionaryValue();
37 info
->SerializeToDict(dict
);
39 scoped_ptr
<base::ListValue
> args(new base::ListValue());
44 ExtensionAccessibilityEventRouter
*
45 ExtensionAccessibilityEventRouter::GetInstance() {
46 return Singleton
<ExtensionAccessibilityEventRouter
>::get();
49 ExtensionAccessibilityEventRouter::ExtensionAccessibilityEventRouter()
53 ExtensionAccessibilityEventRouter::~ExtensionAccessibilityEventRouter() {
54 control_event_callback_
.Reset();
57 void ExtensionAccessibilityEventRouter::SetAccessibilityEnabled(bool enabled
) {
61 bool ExtensionAccessibilityEventRouter::IsAccessibilityEnabled() const {
65 void ExtensionAccessibilityEventRouter::SetControlEventCallbackForTesting(
66 ControlEventCallback control_event_callback
) {
67 DCHECK(control_event_callback_
.is_null());
68 control_event_callback_
= control_event_callback
;
71 void ExtensionAccessibilityEventRouter::ClearControlEventCallback() {
72 control_event_callback_
.Reset();
75 void ExtensionAccessibilityEventRouter::HandleWindowEvent(
77 const AccessibilityWindowInfo
* info
) {
78 if (!control_event_callback_
.is_null())
79 control_event_callback_
.Run(event
, info
);
81 if (event
== ui::AX_EVENT_ALERT
)
85 void ExtensionAccessibilityEventRouter::HandleMenuEvent(
87 const AccessibilityMenuInfo
* info
) {
89 case ui::AX_EVENT_MENU_START
:
90 case ui::AX_EVENT_MENU_POPUP_START
:
93 case ui::AX_EVENT_MENU_END
:
94 case ui::AX_EVENT_MENU_POPUP_END
:
97 case ui::AX_EVENT_FOCUS
:
98 OnControlFocused(info
);
105 void ExtensionAccessibilityEventRouter::HandleControlEvent(
107 const AccessibilityControlInfo
* info
) {
108 if (!control_event_callback_
.is_null())
109 control_event_callback_
.Run(event
, info
);
112 case ui::AX_EVENT_TEXT_CHANGED
:
113 case ui::AX_EVENT_SELECTION_CHANGED
:
116 case ui::AX_EVENT_VALUE_CHANGED
:
117 case ui::AX_EVENT_ALERT
:
118 OnControlAction(info
);
120 case ui::AX_EVENT_FOCUS
:
121 OnControlFocused(info
);
128 void ExtensionAccessibilityEventRouter::OnWindowOpened(
129 const AccessibilityWindowInfo
* info
) {
130 scoped_ptr
<base::ListValue
> args(ControlInfoToEventArguments(info
));
131 DispatchEvent(info
->profile(),
132 experimental_accessibility::OnWindowOpened::kEventName
,
136 void ExtensionAccessibilityEventRouter::OnControlFocused(
137 const AccessibilityControlInfo
* info
) {
138 last_focused_control_dict_
.Clear();
139 info
->SerializeToDict(&last_focused_control_dict_
);
140 scoped_ptr
<base::ListValue
> args(ControlInfoToEventArguments(info
));
141 DispatchEvent(info
->profile(),
142 experimental_accessibility::OnControlFocused::kEventName
,
146 void ExtensionAccessibilityEventRouter::OnControlAction(
147 const AccessibilityControlInfo
* info
) {
148 scoped_ptr
<base::ListValue
> args(ControlInfoToEventArguments(info
));
149 DispatchEvent(info
->profile(),
150 experimental_accessibility::OnControlAction::kEventName
,
154 void ExtensionAccessibilityEventRouter::OnTextChanged(
155 const AccessibilityControlInfo
* info
) {
156 scoped_ptr
<base::ListValue
> args(ControlInfoToEventArguments(info
));
157 DispatchEvent(info
->profile(),
158 experimental_accessibility::OnTextChanged::kEventName
,
162 void ExtensionAccessibilityEventRouter::OnMenuOpened(
163 const AccessibilityMenuInfo
* info
) {
164 scoped_ptr
<base::ListValue
> args(ControlInfoToEventArguments(info
));
165 DispatchEvent(info
->profile(),
166 experimental_accessibility::OnMenuOpened::kEventName
,
170 void ExtensionAccessibilityEventRouter::OnMenuClosed(
171 const AccessibilityMenuInfo
* info
) {
172 scoped_ptr
<base::ListValue
> args(ControlInfoToEventArguments(info
));
173 DispatchEvent(info
->profile(),
174 experimental_accessibility::OnMenuClosed::kEventName
,
178 void ExtensionAccessibilityEventRouter::OnChromeVoxLoadStateChanged(
181 bool make_announcements
) {
182 scoped_ptr
<base::ListValue
> event_args(new base::ListValue());
183 event_args
->Append(base::Value::CreateBooleanValue(loading
));
184 event_args
->Append(base::Value::CreateBooleanValue(make_announcements
));
185 ExtensionAccessibilityEventRouter::DispatchEventToChromeVox(profile
,
186 experimental_accessibility::OnChromeVoxLoadStateChanged::kEventName
,
191 void ExtensionAccessibilityEventRouter::DispatchEventToChromeVox(
193 const char* event_name
,
194 scoped_ptr
<base::ListValue
> event_args
) {
195 extensions::ExtensionSystem
* system
=
196 extensions::ExtensionSystem::Get(profile
);
199 scoped_ptr
<extensions::Event
> event(new extensions::Event(event_name
,
201 system
->event_router()->DispatchEventWithLazyListener(
202 extension_misc::kChromeVoxExtensionId
, event
.Pass());
205 void ExtensionAccessibilityEventRouter::DispatchEvent(
207 const char* event_name
,
208 scoped_ptr
<base::ListValue
> event_args
) {
209 if (!enabled_
|| !profile
)
211 extensions::EventRouter
* event_router
= extensions::EventRouter::Get(profile
);
215 scoped_ptr
<extensions::Event
> event(new extensions::Event(
216 event_name
, event_args
.Pass()));
217 event_router
->BroadcastEvent(event
.Pass());
220 bool AccessibilitySetAccessibilityEnabledFunction::RunSync() {
222 EXTENSION_FUNCTION_VALIDATE(args_
->GetBoolean(0, &enabled
));
223 ExtensionAccessibilityEventRouter::GetInstance()
224 ->SetAccessibilityEnabled(enabled
);
228 bool AccessibilitySetNativeAccessibilityEnabledFunction::RunSync() {
230 EXTENSION_FUNCTION_VALIDATE(args_
->GetBoolean(0, &enabled
));
232 content::BrowserAccessibilityState::GetInstance()->
233 EnableAccessibility();
235 content::BrowserAccessibilityState::GetInstance()->
236 DisableAccessibility();
241 bool AccessibilityGetFocusedControlFunction::RunSync() {
242 // Get the serialized dict from the last focused control and return it.
243 // However, if the dict is empty, that means we haven't seen any focus
244 // events yet, so return null instead.
245 ExtensionAccessibilityEventRouter
*accessibility_event_router
=
246 ExtensionAccessibilityEventRouter::GetInstance();
247 base::DictionaryValue
*last_focused_control_dict
=
248 accessibility_event_router
->last_focused_control_dict();
249 if (last_focused_control_dict
->size()) {
250 SetResult(last_focused_control_dict
->DeepCopyWithoutEmptyChildren());
252 SetResult(base::Value::CreateNullValue());
257 bool AccessibilityGetAlertsForTabFunction::RunSync() {
259 EXTENSION_FUNCTION_VALIDATE(args_
->GetInteger(0, &tab_id
));
261 TabStripModel
* tab_strip
= NULL
;
262 content::WebContents
* contents
= NULL
;
264 if (!extensions::ExtensionTabUtil::GetTabById(tab_id
,
271 error_
= extensions::ErrorUtils::FormatErrorMessage(
272 extensions::tabs_constants::kTabNotFoundError
,
273 base::IntToString(tab_id
));
277 base::ListValue
* alerts_value
= new base::ListValue
;
279 InfoBarService
* infobar_service
= InfoBarService::FromWebContents(contents
);
280 for (size_t i
= 0; i
< infobar_service
->infobar_count(); ++i
) {
281 // TODO(hashimoto): Make other kind of alerts available. crosbug.com/24281
282 ConfirmInfoBarDelegate
* confirm_infobar_delegate
=
283 infobar_service
->infobar_at(i
)->delegate()->AsConfirmInfoBarDelegate();
284 if (confirm_infobar_delegate
) {
285 base::DictionaryValue
* alert_value
= new base::DictionaryValue
;
286 const base::string16 message_text
=
287 confirm_infobar_delegate
->GetMessageText();
288 alert_value
->SetString(keys::kMessageKey
, message_text
);
289 alerts_value
->Append(alert_value
);
293 SetResult(alerts_value
);